Compare commits
16 Commits
0.13.0-bet
...
fix/492
| Author | SHA1 | Date | |
|---|---|---|---|
|
94624bb16d
|
|||
|
aae20f07cc
|
|||
|
6ef8e1ff52
|
|||
|
7fb9675b1e
|
|||
|
d88b478503
|
|||
|
7a735043cd
|
|||
|
e610f32c35
|
|||
| e04a1e15c4 | |||
|
9d401202b4
|
|||
|
6504be6403
|
|||
| d4944dbf35 | |||
|
8d8d4f799d
|
|||
| 0633f24d1b | |||
|
2e062899c7
|
|||
|
fbd7275f03
|
|||
| cedf185e97 |
36
.drone.yml
36
.drone.yml
@ -3,7 +3,7 @@ kind: pipeline
|
|||||||
name: coopcloud.tech/abra
|
name: coopcloud.tech/abra
|
||||||
steps:
|
steps:
|
||||||
- name: make check
|
- name: make check
|
||||||
image: golang:1.24
|
image: golang:1.26
|
||||||
commands:
|
commands:
|
||||||
- make check
|
- make check
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ steps:
|
|||||||
- tag
|
- tag
|
||||||
|
|
||||||
- name: xgettext-go status
|
- name: xgettext-go status
|
||||||
image: golang:1.24-alpine3.22
|
image: golang:1.26-alpine3.22
|
||||||
commands:
|
commands:
|
||||||
- apk add patchutils git make
|
- apk add patchutils git make
|
||||||
- cd /drone/src
|
- cd /drone/src
|
||||||
@ -38,42 +38,14 @@ steps:
|
|||||||
- tag
|
- tag
|
||||||
|
|
||||||
- name: make test
|
- name: make test
|
||||||
image: golang:1.24
|
image: golang:1.26
|
||||||
environment:
|
environment:
|
||||||
ABRA_DIR: $HOME/.abra
|
ABRA_DIR: /root/.abra_test
|
||||||
CATL_URL: https://git.coopcloud.tech/toolshed/recipes-catalogue-json.git
|
|
||||||
commands:
|
commands:
|
||||||
- mkdir -p $HOME/.abra
|
|
||||||
- git clone $CATL_URL $HOME/.abra/catalogue
|
|
||||||
- make test
|
- make test
|
||||||
depends_on:
|
depends_on:
|
||||||
- make check
|
- make check
|
||||||
|
|
||||||
- name: fetch
|
|
||||||
image: docker:git
|
|
||||||
commands:
|
|
||||||
- git fetch --tags
|
|
||||||
depends_on:
|
|
||||||
- make check
|
|
||||||
- make test
|
|
||||||
when:
|
|
||||||
event: tag
|
|
||||||
|
|
||||||
- name: release
|
|
||||||
image: goreleaser/goreleaser:v2.5.1
|
|
||||||
environment:
|
|
||||||
GITEA_TOKEN:
|
|
||||||
from_secret: goreleaser_gitea_token
|
|
||||||
volumes:
|
|
||||||
- name: deps
|
|
||||||
path: /go
|
|
||||||
commands:
|
|
||||||
- goreleaser release
|
|
||||||
depends_on:
|
|
||||||
- fetch
|
|
||||||
when:
|
|
||||||
event: tag
|
|
||||||
|
|
||||||
- name: publish image
|
- name: publish image
|
||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
settings:
|
settings:
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
# Build image
|
# Build image
|
||||||
FROM golang:1.24-alpine AS build
|
FROM golang:1.26-alpine AS build
|
||||||
|
|
||||||
ENV GOPRIVATE=coopcloud.tech
|
ENV GOPRIVATE=coopcloud.tech
|
||||||
|
|
||||||
@ -15,8 +15,7 @@ WORKDIR /app
|
|||||||
|
|
||||||
RUN CGO_ENABLED=0 make build
|
RUN CGO_ENABLED=0 make build
|
||||||
|
|
||||||
# Release image ("slim")
|
FROM alpine:3.22
|
||||||
FROM alpine:3.19.1
|
|
||||||
|
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
|
|||||||
7
Makefile
7
Makefile
@ -2,7 +2,7 @@ ABRA := ./cmd/abra
|
|||||||
XGETTEXT := ./bin/xgettext-go
|
XGETTEXT := ./bin/xgettext-go
|
||||||
COMMIT := $(shell git rev-list -1 HEAD)
|
COMMIT := $(shell git rev-list -1 HEAD)
|
||||||
GOPATH := $(shell go env GOPATH)
|
GOPATH := $(shell go env GOPATH)
|
||||||
GOVERSION := 1.24
|
GOVERSION := 1.26
|
||||||
LDFLAGS := "-X 'main.Commit=$(COMMIT)'"
|
LDFLAGS := "-X 'main.Commit=$(COMMIT)'"
|
||||||
DIST_LDFLAGS := $(LDFLAGS)" -s -w"
|
DIST_LDFLAGS := $(LDFLAGS)" -s -w"
|
||||||
BFLAGS := -v -trimpath
|
BFLAGS := -v -trimpath
|
||||||
@ -40,7 +40,7 @@ check:
|
|||||||
(echo "gofmt: formatting issue - run 'make format' to resolve" && exit 1)
|
(echo "gofmt: formatting issue - run 'make format' to resolve" && exit 1)
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@go test ./... -cover -v
|
@go test ./... -cover -v -p 1
|
||||||
|
|
||||||
find-tests:
|
find-tests:
|
||||||
@find . -name "*_test.go"
|
@find . -name "*_test.go"
|
||||||
@ -86,3 +86,6 @@ build-mo:
|
|||||||
for lang in $(POFILES); do \
|
for lang in $(POFILES); do \
|
||||||
msgfmt $$lang -o $$(echo $$lang | sed 's/.po/.mo/g') --statistics; \
|
msgfmt $$lang -o $$(echo $$lang | sed 's/.po/.mo/g') --statistics; \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
release:
|
||||||
|
@goreleaser release --clean
|
||||||
|
|||||||
@ -157,7 +157,8 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
|||||||
ResolveImage: stack.ResolveImageAlways,
|
ResolveImage: stack.ResolveImageAlways,
|
||||||
Detach: false,
|
Detach: false,
|
||||||
}
|
}
|
||||||
compose, err := appPkg.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
|
||||||
|
compose, err := appPkg.GetAppComposeConfig(composeFiles, app.Env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/i18n"
|
"coopcloud.tech/abra/pkg/i18n"
|
||||||
"coopcloud.tech/abra/pkg/log"
|
"coopcloud.tech/abra/pkg/log"
|
||||||
"coopcloud.tech/abra/pkg/upstream/convert"
|
"coopcloud.tech/abra/pkg/upstream/convert"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
dockerClient "github.com/docker/docker/client"
|
dockerClient "github.com/docker/docker/client"
|
||||||
@ -80,13 +80,13 @@ var AppLabelsCommand = &cobra.Command{
|
|||||||
|
|
||||||
rows = append(rows, []string{i18n.G("RECIPE LABELS"), "---"})
|
rows = append(rows, []string{i18n.G("RECIPE LABELS"), "---"})
|
||||||
|
|
||||||
config, err := app.Recipe.GetComposeConfig(app.Env)
|
config, err := app.Recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var localLabelKeys []string
|
var localLabelKeys []string
|
||||||
var appServiceConfig composetypes.ServiceConfig
|
var appServiceConfig composeGoTypes.ServiceConfig
|
||||||
for _, service := range config.Services {
|
for _, service := range config.Services {
|
||||||
if service.Name == "app" {
|
if service.Name == "app" {
|
||||||
appServiceConfig = service
|
appServiceConfig = service
|
||||||
|
|||||||
@ -262,8 +262,7 @@ func getAppResources(cl *dockerclient.Client, app app.App) (*AppResources, error
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := stack.Deploy{Composefiles: composeFiles, Namespace: app.StackName()}
|
compose, err := appPkg.GetAppComposeConfig(composeFiles, app.Env)
|
||||||
compose, err := appPkg.GetAppComposeConfig(app.Name, opts, app.Env)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"maps"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"coopcloud.tech/abra/cli/internal"
|
"coopcloud.tech/abra/cli/internal"
|
||||||
@ -87,26 +88,19 @@ func showPSOutput(app appPkg.App, cl *dockerClient.Client, deployedVersion, chao
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
deployOpts := stack.Deploy{
|
compose, err := appPkg.GetAppComposeConfig(composeFiles, app.Env)
|
||||||
Composefiles: composeFiles,
|
|
||||||
Namespace: app.StackName(),
|
|
||||||
Prune: false,
|
|
||||||
ResolveImage: stack.ResolveImageAlways,
|
|
||||||
}
|
|
||||||
compose, err := appPkg.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
services := compose.Services
|
services := compose.Services
|
||||||
sort.Slice(services, func(i, j int) bool {
|
|
||||||
return services[i].Name < services[j].Name
|
|
||||||
})
|
|
||||||
|
|
||||||
var rows [][]string
|
var rows [][]string
|
||||||
allContainerStats := make(map[string]map[string]string)
|
allContainerStats := make(map[string]map[string]string)
|
||||||
for _, service := range services {
|
for _, serviceName := range slices.Sorted(maps.Keys(compose.Services)) {
|
||||||
|
service := services[serviceName]
|
||||||
|
|
||||||
filters := filters.NewArgs()
|
filters := filters.NewArgs()
|
||||||
filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), service.Name))
|
filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), service.Name))
|
||||||
|
|
||||||
|
|||||||
@ -173,7 +173,7 @@ beforehand. See "abra app backup" for more.`),
|
|||||||
Detach: false,
|
Detach: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
compose, err := appPkg.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
compose, err := appPkg.GetAppComposeConfig(composeFiles, app.Env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,8 +89,7 @@ Passing "--prune/-p" does not remove those volumes.`),
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := stack.Deploy{Composefiles: composeFiles, Namespace: stackName}
|
compose, err := appPkg.GetAppComposeConfig(composeFiles, app.Env)
|
||||||
compose, err := appPkg.GetAppComposeConfig(app.Name, opts, app.Env)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -185,7 +185,7 @@ beforehand. See "abra app backup" for more.`),
|
|||||||
Detach: false,
|
Detach: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
compose, err := appPkg.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
compose, err := appPkg.GetAppComposeConfig(composeFiles, app.Env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,10 +92,11 @@ func SetBumpType(bumpType string) {
|
|||||||
func GetMainAppImage(recipe recipe.Recipe) (string, error) {
|
func GetMainAppImage(recipe recipe.Recipe) (string, error) {
|
||||||
var path string
|
var path string
|
||||||
|
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, service := range config.Services {
|
for _, service := range config.Services {
|
||||||
if service.Name == "app" {
|
if service.Name == "app" {
|
||||||
img, err := reference.ParseNormalizedNamed(service.Image)
|
img, err := reference.ParseNormalizedNamed(service.Image)
|
||||||
|
|||||||
@ -70,21 +70,6 @@ func ValidateRecipe(args []string, cmdName string) recipe.Recipe {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = chosenRecipe.GetComposeConfig(nil)
|
|
||||||
if err != nil {
|
|
||||||
if cmdName == i18n.G("generate") {
|
|
||||||
if strings.Contains(err.Error(), "missing a compose") {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
log.Warn(err)
|
|
||||||
} else {
|
|
||||||
if strings.Contains(err.Error(), "template_driver is not allowed") {
|
|
||||||
log.Warn(i18n.G("ensure %s recipe compose.* files include \"version: '3.8'\"", recipeName))
|
|
||||||
}
|
|
||||||
log.Fatal(i18n.G("unable to validate recipe: %s", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug(i18n.G("validated %s as recipe argument", recipeName))
|
log.Debug(i18n.G("validated %s as recipe argument", recipeName))
|
||||||
|
|
||||||
return chosenRecipe
|
return chosenRecipe
|
||||||
|
|||||||
@ -97,6 +97,16 @@ your private key and enter your passphrase beforehand.
|
|||||||
log.Fatal(i18n.G("main app service version for %s is empty?", recipe.Name))
|
log.Fatal(i18n.G("main app service version for %s is empty?", recipe.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repo, err := git.PlainOpen(recipe.Dir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
preCommitHead, err := repo.Head()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
isClean, err := gitPkg.IsClean(recipe.Dir)
|
isClean, err := gitPkg.IsClean(recipe.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -201,11 +211,6 @@ likely to change.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if tagString == "" {
|
if tagString == "" {
|
||||||
repo, err := git.PlainOpen(recipe.Dir)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastGitTag tagcmp.Tag
|
var lastGitTag tagcmp.Tag
|
||||||
iter, err := repo.Tags()
|
iter, err := repo.Tags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -282,16 +287,6 @@ likely to change.
|
|||||||
log.Fatal(i18n.G("invalid version %s specified", tagString))
|
log.Fatal(i18n.G("invalid version %s specified", tagString))
|
||||||
}
|
}
|
||||||
|
|
||||||
mainService := "app"
|
|
||||||
label := i18n.G("coop-cloud.${STACK_NAME}.version=%s", tagString)
|
|
||||||
if !internal.Dry {
|
|
||||||
if err := recipe.UpdateLabel("compose.y*ml", mainService, label); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Info(i18n.G("dry run: not syncing label %s for recipe %s", tagString, recipe.Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
previousTagLeftHand := strings.Split(tag, "+")[0]
|
previousTagLeftHand := strings.Split(tag, "+")[0]
|
||||||
newTagStringLeftHand := strings.Split(tagString, "+")[0]
|
newTagStringLeftHand := strings.Split(tagString, "+")[0]
|
||||||
@ -300,24 +295,15 @@ likely to change.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := git.PlainOpen(recipe.Dir)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
preCommitHead, err := repo.Head()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := createReleaseFromTag(recipe, tagString, mainAppVersion); err != nil {
|
if err := createReleaseFromTag(recipe, tagString, mainAppVersion); err != nil {
|
||||||
if cleanErr := cleanTag(recipe, tagString); cleanErr != nil {
|
if cleanErr := cleanTag(recipe, tagString); cleanErr != nil {
|
||||||
log.Fatal(cleanErr)
|
log.Fatal(i18n.G("unable to clean up tag after failed release attempt: %s", cleanErr))
|
||||||
}
|
}
|
||||||
if cleanErr := cleanCommit(recipe, preCommitHead); cleanErr != nil {
|
if resetErr := resetCommit(recipe, preCommitHead); resetErr != nil {
|
||||||
log.Fatal(cleanErr)
|
log.Fatal(i18n.G("unable to reset commit after failed release attempt: %s", resetErr))
|
||||||
}
|
}
|
||||||
log.Fatal(err)
|
log.Error(err)
|
||||||
|
log.Fatal(i18n.G("release failed. any changes made have been reverted"))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -326,10 +312,11 @@ likely to change.
|
|||||||
func GetImageVersions(recipe recipePkg.Recipe) (map[string]string, error) {
|
func GetImageVersions(recipe recipePkg.Recipe) (map[string]string, error) {
|
||||||
services := make(map[string]string)
|
services := make(map[string]string)
|
||||||
|
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
missingTag := false
|
missingTag := false
|
||||||
for _, service := range config.Services {
|
for _, service := range config.Services {
|
||||||
if service.Image == "" {
|
if service.Image == "" {
|
||||||
@ -375,23 +362,14 @@ func createReleaseFromTag(recipe recipePkg.Recipe, tagString, mainAppVersion str
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tag, err := tagcmp.Parse(tagString)
|
mainService := "app"
|
||||||
if err != nil {
|
label := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", tagString)
|
||||||
return err
|
if !internal.Dry {
|
||||||
}
|
if err := recipe.UpdateLabel("compose.y*ml", mainService, label); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
if tag.MissingMinor {
|
}
|
||||||
tag.Minor = "0"
|
} else {
|
||||||
tag.MissingMinor = false
|
log.Info(i18n.G("dry run: not syncing label %s for recipe %s", tagString, recipe.Name))
|
||||||
}
|
|
||||||
|
|
||||||
if tag.MissingPatch {
|
|
||||||
tag.Patch = "0"
|
|
||||||
tag.MissingPatch = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if tagString == "" {
|
|
||||||
tagString = fmt.Sprintf("%s+%s", tag.String(), mainAppVersion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addReleaseNotes(recipe, tagString); err != nil {
|
if err := addReleaseNotes(recipe, tagString); err != nil {
|
||||||
@ -587,9 +565,10 @@ func pushRelease(recipe recipePkg.Recipe, tagString string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanCommit soft removes the latest release commit. No change are lost the
|
// resetCommit hard resets to the state before release was started.
|
||||||
// the commit itself is removed. This is the equivalent of `git reset HEAD~1`.
|
// This will only remove changes made by the release process due to requiring
|
||||||
func cleanCommit(recipe recipePkg.Recipe, head *plumbing.Reference) error {
|
// a clean working directory.
|
||||||
|
func resetCommit(recipe recipePkg.Recipe, head *plumbing.Reference) error {
|
||||||
repo, err := git.PlainOpen(recipe.Dir)
|
repo, err := git.PlainOpen(recipe.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(i18n.G("unable to open repo in %s: %s", recipe.Dir, err))
|
return errors.New(i18n.G("unable to open repo in %s: %s", recipe.Dir, err))
|
||||||
@ -600,12 +579,12 @@ func cleanCommit(recipe recipePkg.Recipe, head *plumbing.Reference) error {
|
|||||||
return errors.New(i18n.G("unable to open work tree in %s: %s", recipe.Dir, err))
|
return errors.New(i18n.G("unable to open work tree in %s: %s", recipe.Dir, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := &git.ResetOptions{Commit: head.Hash(), Mode: git.MixedReset}
|
opts := &git.ResetOptions{Commit: head.Hash(), Mode: git.HardReset}
|
||||||
if err := worktree.Reset(opts); err != nil {
|
if err := worktree.Reset(opts); err != nil {
|
||||||
return errors.New(i18n.G("unable to soft reset %s: %s", recipe.Dir, err))
|
return errors.New(i18n.G("unable to hard reset %s: %s", recipe.Dir, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug(i18n.G("removed freshly created commit"))
|
log.Debug(i18n.G("reset commit to pre-release state"))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,7 +124,7 @@ interface.`),
|
|||||||
log.Debug(i18n.G("did not find versions file for %s", recipe.Name))
|
log.Debug(i18n.G("did not find versions file for %s", recipe.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
109
go.mod
109
go.mod
@ -1,8 +1,6 @@
|
|||||||
module coopcloud.tech/abra
|
module coopcloud.tech/abra
|
||||||
|
|
||||||
go 1.24.0
|
go 1.26.0
|
||||||
|
|
||||||
toolchain go1.24.1
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
coopcloud.tech/tagcmp v0.0.0-20250818180036-0ec1b205b5ca
|
coopcloud.tech/tagcmp v0.0.0-20250818180036-0ec1b205b5ca
|
||||||
@ -10,19 +8,20 @@ require (
|
|||||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||||
github.com/charmbracelet/bubbletea v1.3.10
|
github.com/charmbracelet/bubbletea v1.3.10
|
||||||
github.com/charmbracelet/lipgloss v1.1.0
|
github.com/charmbracelet/lipgloss v1.1.0
|
||||||
github.com/charmbracelet/log v0.4.2
|
github.com/charmbracelet/log v1.0.0
|
||||||
|
github.com/compose-spec/compose-go/v2 v2.10.1
|
||||||
github.com/distribution/reference v0.6.0
|
github.com/distribution/reference v0.6.0
|
||||||
github.com/docker/cli v28.4.0+incompatible
|
github.com/docker/cli v28.4.0+incompatible
|
||||||
github.com/docker/docker v28.5.2+incompatible
|
github.com/docker/docker v28.5.2+incompatible
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
github.com/go-git/go-git/v5 v5.16.2
|
github.com/go-git/go-git/v5 v5.17.2
|
||||||
github.com/google/go-cmp v0.7.0
|
github.com/google/go-cmp v0.7.0
|
||||||
github.com/leonelquinteros/gotext v1.7.2
|
github.com/leonelquinteros/gotext v1.7.2
|
||||||
github.com/moby/sys/signal v0.7.1
|
github.com/moby/sys/signal v0.7.1
|
||||||
github.com/moby/term v0.5.2
|
github.com/moby/term v0.5.2
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/schollz/progressbar/v3 v3.18.0
|
github.com/schollz/progressbar/v3 v3.19.0
|
||||||
golang.org/x/term v0.35.0
|
golang.org/x/term v0.41.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gotest.tools/v3 v3.5.2
|
gotest.tools/v3 v3.5.2
|
||||||
)
|
)
|
||||||
@ -30,27 +29,28 @@ require (
|
|||||||
require (
|
require (
|
||||||
dario.cat/mergo v1.0.2 // indirect
|
dario.cat/mergo v1.0.2 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
github.com/BurntSushi/toml v1.6.0 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
github.com/ProtonMail/go-crypto v1.4.1 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/charmbracelet/colorprofile v0.3.2 // indirect
|
github.com/charmbracelet/colorprofile v0.4.3 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.10.2 // indirect
|
github.com/charmbracelet/x/ansi v0.11.6 // indirect
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
|
||||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 // indirect
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 // indirect
|
||||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
github.com/charmbracelet/x/term v0.2.2 // indirect
|
||||||
github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
|
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||||
github.com/cloudflare/circl v1.6.1 // indirect
|
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||||
|
github.com/cloudflare/circl v1.6.3 // indirect
|
||||||
github.com/containerd/errdefs v1.0.0 // indirect
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/containerd/platforms v0.2.1 // indirect
|
github.com/containerd/platforms v0.2.1 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.5.0 // indirect
|
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.6.0 // indirect
|
github.com/docker/go-connections v0.6.0 // indirect
|
||||||
@ -61,26 +61,27 @@ require (
|
|||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // indirect
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
github.com/go-git/go-billy/v5 v5.8.0 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
github.com/go-logfmt/logfmt v0.6.1 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.4.0 // indirect
|
github.com/kevinburke/ssh_config v1.6.0 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.5 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.19 // indirect
|
github.com/mattn/go-runewidth v0.0.21 // indirect
|
||||||
|
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
@ -89,7 +90,7 @@ require (
|
|||||||
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
||||||
github.com/moby/sys/user v0.4.0 // indirect
|
github.com/moby/sys/user v0.4.0 // indirect
|
||||||
github.com/moby/sys/userns v0.1.0 // indirect
|
github.com/moby/sys/userns v0.1.0 // indirect
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.1.0 // indirect
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
github.com/muesli/termenv v0.16.0 // indirect
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
@ -100,40 +101,44 @@ require (
|
|||||||
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
github.com/prometheus/common v0.66.1 // indirect
|
github.com/prometheus/common v0.67.5 // indirect
|
||||||
github.com/prometheus/procfs v0.17.0 // indirect
|
github.com/prometheus/procfs v0.20.1 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
|
||||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||||
|
github.com/skeema/knownhosts v1.3.2 // indirect
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
|
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
go.opentelemetry.io/otel v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/metric v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk/metric v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
go.opentelemetry.io/otel/trace v1.42.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.8.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/crypto v0.42.0 // indirect
|
go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
|
golang.org/x/crypto v0.49.0 // indirect
|
||||||
golang.org/x/net v0.44.0 // indirect
|
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
|
||||||
golang.org/x/text v0.29.0 // indirect
|
golang.org/x/net v0.52.0 // indirect
|
||||||
golang.org/x/time v0.13.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4 // indirect
|
golang.org/x/text v0.35.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 // indirect
|
golang.org/x/time v0.15.0 // indirect
|
||||||
google.golang.org/grpc v1.75.1 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||||
google.golang.org/protobuf v1.36.9 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||||
|
google.golang.org/grpc v1.80.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
@ -142,12 +147,12 @@ require (
|
|||||||
github.com/containers/image v3.0.2+incompatible
|
github.com/containers/image v3.0.2+incompatible
|
||||||
github.com/containers/storage v1.38.2 // indirect
|
github.com/containers/storage v1.38.2 // indirect
|
||||||
github.com/decentral1se/passgen v1.0.1
|
github.com/decentral1se/passgen v1.0.1
|
||||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
github.com/docker/docker-credential-helpers v0.9.5 // indirect
|
||||||
github.com/fvbommel/sortorder v1.1.0 // indirect
|
github.com/fvbommel/sortorder v1.1.0 // indirect
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/gorilla/mux v1.8.1 // indirect
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.8
|
github.com/hashicorp/go-retryablehttp v0.7.8
|
||||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
github.com/moby/patternmatcher v0.6.1 // indirect
|
||||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/prometheus/client_golang v1.23.2 // indirect
|
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||||
@ -156,7 +161,7 @@ require (
|
|||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
golang.org/x/sys v0.36.0
|
golang.org/x/sys v0.42.0
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/docker/cli v28.4.0+incompatible => git.coopcloud.tech/toolshed/docker-cli v28.5.3-0.20260202112816-30df2d0b3a00+incompatible
|
replace github.com/docker/cli v28.4.0+incompatible => git.coopcloud.tech/toolshed/docker-cli v28.5.3-0.20260202112816-30df2d0b3a00+incompatible
|
||||||
|
|||||||
214
go.sum
214
go.sum
@ -51,8 +51,8 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
|
|||||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
@ -81,8 +81,8 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0
|
|||||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
|
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
|
||||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
github.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM=
|
||||||
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
github.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=
|
||||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
@ -136,20 +136,20 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
|||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
||||||
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
|
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
|
||||||
github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqITmrvb1uTIiI=
|
github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
|
||||||
github.com/charmbracelet/colorprofile v0.3.2/go.mod h1:mTD5XzNeWHj8oqHb+S1bssQb7vIHbepiebQ2kPKVKbI=
|
github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
|
||||||
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||||
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||||
github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
|
github.com/charmbracelet/log v1.0.0 h1:HVVVMmfOorfj3BA9i8X8UL69Hoz9lI0PYwXfJvOdRc4=
|
||||||
github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
|
github.com/charmbracelet/log v1.0.0/go.mod h1:uYgY3SmLpwJWxmlrPwXvzVYujxis1vAKRV/0VQB7yWA=
|
||||||
github.com/charmbracelet/x/ansi v0.10.2 h1:ith2ArZS0CJG30cIUfID1LXN7ZFXRCww6RUvAPA+Pzw=
|
github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
|
||||||
github.com/charmbracelet/x/ansi v0.10.2/go.mod h1:HbLdJjQH4UH4AqA2HpRWuWNluRE6zxJH/yteYEYCFa8=
|
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
|
github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
|
||||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
||||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
|
||||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||||
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
||||||
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
|
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
|
||||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
||||||
@ -165,15 +165,19 @@ github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJ
|
|||||||
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||||
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
|
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
|
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
|
||||||
github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
|
github.com/compose-spec/compose-go/v2 v2.10.1 h1:mFbXobojGRFIVi1UknrvaDAZ+PkJfyjqkA1yseh+vAU=
|
||||||
|
github.com/compose-spec/compose-go/v2 v2.10.1/go.mod h1:Ohac1SzhO/4fXXrzWIztIVB6ckmKBv1Nt5Z5mGVESUg=
|
||||||
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
|
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
|
||||||
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
|
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
|
||||||
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
|
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
|
||||||
@ -297,8 +301,8 @@ github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
|||||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||||
github.com/cyphar/filepath-securejoin v0.5.0 h1:hIAhkRBMQ8nIeuVwcAoymp7MY4oherZdAxD+m0u9zaw=
|
github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
|
||||||
github.com/cyphar/filepath-securejoin v0.5.0/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
|
||||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
||||||
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
||||||
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
|
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
|
||||||
@ -316,6 +320,8 @@ github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11
|
|||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
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/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
|
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||||
|
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||||
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
|
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
|
||||||
@ -327,8 +333,8 @@ github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r
|
|||||||
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
||||||
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||||
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY=
|
||||||
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
@ -387,12 +393,12 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
|||||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0=
|
||||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM=
|
github.com/go-git/go-git/v5 v5.17.2 h1:B+nkdlxdYrvyFK4GPXVU8w1U+YkbsgciIR7f2sZJ104=
|
||||||
github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
github.com/go-git/go-git/v5 v5.17.2/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
@ -401,8 +407,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
|
||||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk=
|
||||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
@ -423,8 +429,8 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
|
|||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||||
@ -524,8 +530,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
|
|||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
@ -573,8 +579,8 @@ github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVE
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
|
github.com/kevinburke/ssh_config v1.6.0 h1:J1FBfmuVosPHf5GRdltRLhPJtJpTlMdKTBjRgTaQBFY=
|
||||||
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
github.com/kevinburke/ssh_config v1.6.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
@ -582,8 +588,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||||||
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
@ -607,8 +613,8 @@ github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+
|
|||||||
github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8=
|
github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8=
|
||||||
github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
|
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
|
||||||
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
|
github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
|
||||||
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
@ -626,10 +632,11 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
|
github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=
|
||||||
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||||
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||||
|
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/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||||
github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
@ -653,8 +660,8 @@ github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6U
|
|||||||
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
||||||
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
|
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
|
||||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
|
||||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||||
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||||
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||||
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
|
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
|
||||||
@ -679,8 +686,9 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
|||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=
|
||||||
|
github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=
|
||||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||||
@ -779,8 +787,8 @@ github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7q
|
|||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
|
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||||
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||||
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
@ -791,8 +799,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
|
|||||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
|
github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
|
||||||
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
|
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
@ -804,9 +812,11 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
|||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
||||||
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
|
||||||
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
|
github.com/schollz/progressbar/v3 v3.19.0 h1:Ea18xuIRQXLAUidVDox3AbwfUhD0/1IvohyTutOIFoc=
|
||||||
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
github.com/schollz/progressbar/v3 v3.19.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
||||||
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
|
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
||||||
@ -821,10 +831,10 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
|||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||||
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg=
|
||||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
github.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
@ -891,6 +901,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
|
|||||||
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
||||||
|
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
@ -912,39 +924,41 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=
|
||||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
|
||||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 h1:MdKucPl/HbzckWWEisiNqMPhRrAOQX8r4jTuGr636gk=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0/go.mod h1:RolT8tWtfHcjajEH5wFIZ4Dgh5jpPdFXYV9pTAk/qjc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.opentelemetry.io/proto/otlp v1.8.0 h1:fRAZQDcAFHySxpJ1TwlA1cJ4tvcrw7nXl9xWWC8N5CE=
|
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
|
||||||
go.opentelemetry.io/proto/otlp v1.8.0/go.mod h1:tIeYOeNBU4cvmPqpaji1P+KbB4Oloai8wN4rWzRrFF0=
|
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
|
go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go=
|
||||||
|
go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
||||||
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@ -963,8 +977,8 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP
|
|||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@ -975,8 +989,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
|
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
|
||||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
|
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@ -1040,8 +1054,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
|||||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -1059,6 +1073,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -1137,13 +1153,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -1153,16 +1169,16 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
|
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||||
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@ -1212,8 +1228,8 @@ 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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||||
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
@ -1258,10 +1274,10 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG
|
|||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||||
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4 h1:8XJ4pajGwOlasW+L13MnEGA8W4115jJySQtVfS2/IBU=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4/go.mod h1:NnuHhy+bxcg30o7FnVAZbXsPHUDQ9qKWAQKCD7VxFtk=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 h1:i8QOKZfYg6AbGVZzUAY3LrNWCKF8O6zFisU9Wl9RER4=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
@ -1281,8 +1297,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp
|
|||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
|
||||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@ -1296,8 +1312,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
|||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
|
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
|
||||||
|
|||||||
@ -18,10 +18,10 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/recipe"
|
"coopcloud.tech/abra/pkg/recipe"
|
||||||
"coopcloud.tech/abra/pkg/upstream/convert"
|
"coopcloud.tech/abra/pkg/upstream/convert"
|
||||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
|
|
||||||
"coopcloud.tech/abra/pkg/log"
|
"coopcloud.tech/abra/pkg/log"
|
||||||
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/schollz/progressbar/v3"
|
"github.com/schollz/progressbar/v3"
|
||||||
)
|
)
|
||||||
@ -179,8 +179,7 @@ func (a App) Filters(appendServiceNames, exactMatch bool, services ...string) (f
|
|||||||
return filters, err
|
return filters, err
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := stack.Deploy{Composefiles: composeFiles}
|
compose, err := GetAppComposeConfig(composeFiles, a.Env)
|
||||||
compose, err := GetAppComposeConfig(a.Recipe.Name, opts, a.Env)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return filters, err
|
return filters, err
|
||||||
}
|
}
|
||||||
@ -333,8 +332,7 @@ func GetAppServiceNames(appName string) ([]string, error) {
|
|||||||
return serviceNames, err
|
return serviceNames, err
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := stack.Deploy{Composefiles: composeFiles}
|
compose, err := GetAppComposeConfig(composeFiles, app.Env)
|
||||||
compose, err := GetAppComposeConfig(app.Recipe.Name, opts, app.Env)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return serviceNames, err
|
return serviceNames, err
|
||||||
}
|
}
|
||||||
@ -490,13 +488,18 @@ func GetAppStatuses(apps []App, MachineReadable bool) (map[string]map[string]str
|
|||||||
// GetAppComposeConfig retrieves a compose specification for a recipe. This
|
// GetAppComposeConfig retrieves a compose specification for a recipe. This
|
||||||
// specification is the result of a merge of all the compose.**.yml files in
|
// specification is the result of a merge of all the compose.**.yml files in
|
||||||
// the recipe repository.
|
// the recipe repository.
|
||||||
func GetAppComposeConfig(recipe string, opts stack.Deploy, appEnv envfile.AppEnv) (*composetypes.Config, error) {
|
func GetAppComposeConfig(composeFiles []string, appEnv envfile.AppEnv) (*composeGoTypes.Project, error) {
|
||||||
compose, err := loader.LoadComposefile(opts, appEnv)
|
compose, err := loader.LoadCompose(loader.LoadConf{ComposeFiles: composeFiles, AppEnv: appEnv})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &composetypes.Config{}, err
|
return &composeGoTypes.Project{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug(i18n.G("retrieved %s for %s", compose.Filename, recipe))
|
recipeName, exists := appEnv["RECIPE"]
|
||||||
|
if !exists {
|
||||||
|
recipeName, _ = appEnv["TYPE"]
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug(i18n.G("retrieved %s for %s", compose.Name, recipeName))
|
||||||
|
|
||||||
return compose, nil
|
return compose, nil
|
||||||
}
|
}
|
||||||
@ -504,7 +507,7 @@ func GetAppComposeConfig(recipe string, opts stack.Deploy, appEnv envfile.AppEnv
|
|||||||
// ExposeAllEnv exposes all env variables to the app container
|
// ExposeAllEnv exposes all env variables to the app container
|
||||||
func ExposeAllEnv(
|
func ExposeAllEnv(
|
||||||
stackName string,
|
stackName string,
|
||||||
compose *composetypes.Config,
|
compose *composeGoTypes.Project,
|
||||||
appEnv envfile.AppEnv,
|
appEnv envfile.AppEnv,
|
||||||
toDeployVersion string) {
|
toDeployVersion string) {
|
||||||
for _, service := range compose.Services {
|
for _, service := range compose.Services {
|
||||||
|
|||||||
@ -10,46 +10,83 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"coopcloud.tech/abra/pkg/envfile"
|
"coopcloud.tech/abra/pkg/envfile"
|
||||||
"coopcloud.tech/abra/pkg/recipe"
|
"coopcloud.tech/abra/pkg/recipe"
|
||||||
testPkg "coopcloud.tech/abra/pkg/test"
|
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
||||||
|
"coopcloud.tech/abra/pkg/test"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
expectedAppEnv = envfile.AppEnv{
|
||||||
|
"DOMAIN": test.AppName,
|
||||||
|
"RECIPE": test.RecipeName,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedApp = appPkg.App{
|
||||||
|
Name: test.AppName,
|
||||||
|
Recipe: recipePkg.Get(expectedAppEnv["RECIPE"]),
|
||||||
|
Domain: expectedAppEnv["DOMAIN"],
|
||||||
|
Env: expectedAppEnv,
|
||||||
|
Path: expectedAppFile.Path,
|
||||||
|
Server: expectedAppFile.Server,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedAppFile = appPkg.AppFile{
|
||||||
|
Path: test.AppEnvPath,
|
||||||
|
Server: test.ServerName,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedAppFiles = map[string]appPkg.AppFile{
|
||||||
|
test.AppName: expectedAppFile,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func TestNewApp(t *testing.T) {
|
func TestNewApp(t *testing.T) {
|
||||||
app, err := appPkg.NewApp(testPkg.ExpectedAppEnv, testPkg.AppName, testPkg.ExpectedAppFile)
|
app, err := appPkg.NewApp(expectedAppEnv, test.AppName, expectedAppFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(app, testPkg.ExpectedApp) {
|
|
||||||
t.Fatalf("did not get expected app type. Expected: %s; Got: %s", app, testPkg.ExpectedApp)
|
if !reflect.DeepEqual(app, expectedApp) {
|
||||||
|
t.Fatalf("did not get expected app type. Expected: %s; Got: %s", app, expectedApp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadAppEnvFile(t *testing.T) {
|
func TestReadAppEnvFile(t *testing.T) {
|
||||||
app, err := appPkg.ReadAppEnvFile(testPkg.ExpectedAppFile, testPkg.AppName)
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
app, err := appPkg.ReadAppEnvFile(expectedAppFile, test.AppName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(app, testPkg.ExpectedApp) {
|
|
||||||
t.Fatalf("did not get expected app type. Expected: %s; Got: %s", app, testPkg.ExpectedApp)
|
if !reflect.DeepEqual(app, expectedApp) {
|
||||||
|
t.Fatalf("did not get expected app type. Expected: %s; Got: %s", app, expectedApp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetApp(t *testing.T) {
|
func TestGetApp(t *testing.T) {
|
||||||
app, err := appPkg.GetApp(testPkg.ExpectedAppFiles, testPkg.AppName)
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
app, err := appPkg.GetApp(expectedAppFiles, test.AppName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(app, testPkg.ExpectedApp) {
|
|
||||||
t.Fatalf("did not get expected app type. Expected: %s; Got: %s", app, testPkg.ExpectedApp)
|
if !reflect.DeepEqual(app, expectedApp) {
|
||||||
|
t.Fatalf("did not get expected app type. Expected: %s; Got: %s", app, expectedApp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetComposeFiles(t *testing.T) {
|
func TestGetComposeFiles(t *testing.T) {
|
||||||
r := recipe.Get("abra-test-recipe")
|
test.Setup()
|
||||||
err := r.EnsureExists()
|
t.Cleanup(func() { test.Teardown() })
|
||||||
if err != nil {
|
|
||||||
|
r := recipe.Get(test.AbraTestRecipe)
|
||||||
|
if err := r.EnsureExists(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +131,10 @@ func TestGetComposeFiles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetComposeFilesError(t *testing.T) {
|
func TestGetComposeFilesError(t *testing.T) {
|
||||||
r := recipe.Get("abra-test-recipe")
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
r := recipe.Get(test.AbraTestRecipe)
|
||||||
err := r.EnsureExists()
|
err := r.EnsureExists()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -186,26 +226,32 @@ func TestFilters(t *testing.T) {
|
|||||||
|
|
||||||
func compareFilter(t *testing.T, f1 filters.Args, f2 map[string]map[string]bool) {
|
func compareFilter(t *testing.T, f1 filters.Args, f2 map[string]map[string]bool) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
j1, err := f1.MarshalJSON()
|
j1, err := f1.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
j2, err := json.Marshal(f2)
|
j2, err := json.Marshal(f2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff := cmp.Diff(string(j2), string(j1)); diff != "" {
|
if diff := cmp.Diff(string(j2), string(j1)); diff != "" {
|
||||||
t.Errorf("filters mismatch (-want +got):\n%s", diff)
|
t.Errorf("filters mismatch (-want +got):\n%s", diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteRecipeVersionOverwrite(t *testing.T) {
|
func TestWriteRecipeVersionOverwrite(t *testing.T) {
|
||||||
app, err := appPkg.GetApp(testPkg.ExpectedAppFiles, testPkg.AppName)
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
app, err := appPkg.GetApp(expectedAppFiles, test.AppName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
if err := app.WipeRecipeVersion(); err != nil {
|
if err := app.WipeRecipeVersion(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -217,7 +263,7 @@ func TestWriteRecipeVersionOverwrite(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app, err = appPkg.GetApp(testPkg.ExpectedAppFiles, testPkg.AppName)
|
app, err = appPkg.GetApp(expectedAppFiles, test.AppName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -226,7 +272,10 @@ func TestWriteRecipeVersionOverwrite(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteRecipeVersionUnknown(t *testing.T) {
|
func TestWriteRecipeVersionUnknown(t *testing.T) {
|
||||||
app, err := appPkg.GetApp(testPkg.ExpectedAppFiles, testPkg.AppName)
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
app, err := appPkg.GetApp(expectedAppFiles, test.AppName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,12 +7,12 @@ import (
|
|||||||
|
|
||||||
"coopcloud.tech/abra/pkg/i18n"
|
"coopcloud.tech/abra/pkg/i18n"
|
||||||
"coopcloud.tech/abra/pkg/log"
|
"coopcloud.tech/abra/pkg/log"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetRecipeLabel adds the label 'coop-cloud.${STACK_NAME}.recipe=${RECIPE}' to the app container
|
// SetRecipeLabel adds the label 'coop-cloud.${STACK_NAME}.recipe=${RECIPE}' to the app container
|
||||||
// to signal which recipe is connected to the deployed app
|
// to signal which recipe is connected to the deployed app
|
||||||
func SetRecipeLabel(compose *composetypes.Config, stackName string, recipe string) {
|
func SetRecipeLabel(compose *composeGoTypes.Project, stackName string, recipe string) {
|
||||||
for _, service := range compose.Services {
|
for _, service := range compose.Services {
|
||||||
if service.Name == "app" {
|
if service.Name == "app" {
|
||||||
log.Debug(i18n.G("set recipe label 'coop-cloud.%s.recipe' to %s for %s", stackName, recipe, stackName))
|
log.Debug(i18n.G("set recipe label 'coop-cloud.%s.recipe' to %s for %s", stackName, recipe, stackName))
|
||||||
@ -24,7 +24,7 @@ func SetRecipeLabel(compose *composetypes.Config, stackName string, recipe strin
|
|||||||
|
|
||||||
// SetChaosLabel adds the label 'coop-cloud.${STACK_NAME}.chaos=true/false' to the app container
|
// SetChaosLabel adds the label 'coop-cloud.${STACK_NAME}.chaos=true/false' to the app container
|
||||||
// to signal if the app is deployed in chaos mode
|
// to signal if the app is deployed in chaos mode
|
||||||
func SetChaosLabel(compose *composetypes.Config, stackName string, chaos bool) {
|
func SetChaosLabel(compose *composeGoTypes.Project, stackName string, chaos bool) {
|
||||||
for _, service := range compose.Services {
|
for _, service := range compose.Services {
|
||||||
if service.Name == "app" {
|
if service.Name == "app" {
|
||||||
log.Debug(i18n.G("set label 'coop-cloud.%s.chaos' to %v for %s", stackName, chaos, stackName))
|
log.Debug(i18n.G("set label 'coop-cloud.%s.chaos' to %v for %s", stackName, chaos, stackName))
|
||||||
@ -35,7 +35,7 @@ func SetChaosLabel(compose *composetypes.Config, stackName string, chaos bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetChaosVersionLabel adds the label 'coop-cloud.${STACK_NAME}.chaos-version=$(GIT_COMMIT)' to the app container
|
// SetChaosVersionLabel adds the label 'coop-cloud.${STACK_NAME}.chaos-version=$(GIT_COMMIT)' to the app container
|
||||||
func SetChaosVersionLabel(compose *composetypes.Config, stackName string, chaosVersion string) {
|
func SetChaosVersionLabel(compose *composeGoTypes.Project, stackName string, chaosVersion string) {
|
||||||
for _, service := range compose.Services {
|
for _, service := range compose.Services {
|
||||||
if service.Name == "app" {
|
if service.Name == "app" {
|
||||||
log.Debug(i18n.G("set label 'coop-cloud.%s.chaos-version' to %v for %s", stackName, chaosVersion, stackName))
|
log.Debug(i18n.G("set label 'coop-cloud.%s.chaos-version' to %v for %s", stackName, chaosVersion, stackName))
|
||||||
@ -45,7 +45,7 @@ func SetChaosVersionLabel(compose *composetypes.Config, stackName string, chaosV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetVersionLabel(compose *composetypes.Config, stackName string, version string) {
|
func SetVersionLabel(compose *composeGoTypes.Project, stackName string, version string) {
|
||||||
for _, service := range compose.Services {
|
for _, service := range compose.Services {
|
||||||
if service.Name == "app" {
|
if service.Name == "app" {
|
||||||
log.Debug(i18n.G("set label 'coop-cloud.%s.version' to %v for %s", stackName, version, stackName))
|
log.Debug(i18n.G("set label 'coop-cloud.%s.version' to %v for %s", stackName, version, stackName))
|
||||||
@ -56,7 +56,7 @@ func SetVersionLabel(compose *composetypes.Config, stackName string, version str
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetLabel reads docker labels in the format of "coop-cloud.${STACK_NAME}.${LABEL}" from the local compose files
|
// GetLabel reads docker labels in the format of "coop-cloud.${STACK_NAME}.${LABEL}" from the local compose files
|
||||||
func GetLabel(compose *composetypes.Config, stackName string, label string) string {
|
func GetLabel(compose *composeGoTypes.Project, stackName string, label string) string {
|
||||||
for _, service := range compose.Services {
|
for _, service := range compose.Services {
|
||||||
if service.Name == "app" {
|
if service.Name == "app" {
|
||||||
labelKey := fmt.Sprintf("coop-cloud.%s.%s", stackName, label)
|
labelKey := fmt.Sprintf("coop-cloud.%s.%s", stackName, label)
|
||||||
@ -73,7 +73,7 @@ func GetLabel(compose *composetypes.Config, stackName string, label string) stri
|
|||||||
// GetTimeoutFromLabel reads the timeout value from docker label
|
// GetTimeoutFromLabel reads the timeout value from docker label
|
||||||
// `coop-cloud.${STACK_NAME}.timeout=...` if present. A value is present if the
|
// `coop-cloud.${STACK_NAME}.timeout=...` if present. A value is present if the
|
||||||
// operator uses a `TIMEOUT=...` in their app env.
|
// operator uses a `TIMEOUT=...` in their app env.
|
||||||
func GetTimeoutFromLabel(compose *composetypes.Config, stackName string) (int, error) {
|
func GetTimeoutFromLabel(compose *composeGoTypes.Project, stackName string) (int, error) {
|
||||||
var timeout int
|
var timeout int
|
||||||
|
|
||||||
if timeoutLabel := GetLabel(compose, stackName, "timeout"); timeoutLabel != "" {
|
if timeoutLabel := GetLabel(compose, stackName, "timeout"); timeoutLabel != "" {
|
||||||
|
|||||||
@ -4,15 +4,15 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
appPkg "coopcloud.tech/abra/pkg/app"
|
appPkg "coopcloud.tech/abra/pkg/app"
|
||||||
|
"coopcloud.tech/abra/pkg/test"
|
||||||
testPkg "coopcloud.tech/abra/pkg/test"
|
testPkg "coopcloud.tech/abra/pkg/test"
|
||||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetTimeoutFromLabel(t *testing.T) {
|
func TestGetTimeoutFromLabel(t *testing.T) {
|
||||||
testPkg.MkServerAppRecipe()
|
test.Setup()
|
||||||
defer testPkg.RmServerAppRecipe()
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
configuredTimeout string
|
configuredTimeout string
|
||||||
@ -25,7 +25,7 @@ func TestGetTimeoutFromLabel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
app, err := appPkg.GetApp(testPkg.ExpectedAppFiles, testPkg.AppName)
|
app, err := appPkg.GetApp(expectedAppFiles, testPkg.AppName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -39,15 +39,8 @@ func TestGetTimeoutFromLabel(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
deployOpts := stack.Deploy{
|
app.Env["STACK_NAME"] = app.StackName()
|
||||||
Composefiles: composeFiles,
|
compose, err := appPkg.GetAppComposeConfig(composeFiles, app.Env)
|
||||||
Namespace: app.StackName(),
|
|
||||||
Prune: false,
|
|
||||||
ResolveImage: stack.ResolveImageAlways,
|
|
||||||
Detach: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
compose, err := appPkg.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -120,7 +120,7 @@ func CommandNameComplete(appName string) ([]string, cobra.ShellCompDirective) {
|
|||||||
func SecretComplete(recipeName string) ([]string, cobra.ShellCompDirective) {
|
func SecretComplete(recipeName string) ([]string, cobra.ShellCompDirective) {
|
||||||
r := recipe.Get(recipeName)
|
r := recipe.Get(recipeName)
|
||||||
|
|
||||||
config, err := r.GetComposeConfig(nil)
|
config, err := r.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := i18n.G("autocomplete failed: %s", err)
|
err := i18n.G("autocomplete failed: %s", err)
|
||||||
return []string{err}, cobra.ShellCompDirectiveError
|
return []string{err}, cobra.ShellCompDirectiveError
|
||||||
|
|||||||
@ -10,8 +10,9 @@ import (
|
|||||||
func TestFindAbraConfig(t *testing.T) {
|
func TestFindAbraConfig(t *testing.T) {
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
Dir string
|
Dir string
|
||||||
Config string
|
Config string
|
||||||
@ -51,8 +52,9 @@ func TestFindAbraConfig(t *testing.T) {
|
|||||||
func TestLoadAbraConfigGetAbraDir(t *testing.T) {
|
func TestLoadAbraConfigGetAbraDir(t *testing.T) {
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Setenv("ABRA_DIR", "")
|
t.Setenv("ABRA_DIR", "")
|
||||||
|
|
||||||
t.Run("default", func(t *testing.T) {
|
t.Run("default", func(t *testing.T) {
|
||||||
@ -67,7 +69,7 @@ func TestLoadAbraConfigGetAbraDir(t *testing.T) {
|
|||||||
t.Cleanup(func() { os.Chdir(wd) })
|
t.Cleanup(func() { os.Chdir(wd) })
|
||||||
err = os.Chdir(filepath.Join(wd, "testdata/abraconfig1"))
|
err = os.Chdir(filepath.Join(wd, "testdata/abraconfig1"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := LoadAbraConfig()
|
cfg := LoadAbraConfig()
|
||||||
@ -81,7 +83,7 @@ func TestLoadAbraConfigGetAbraDir(t *testing.T) {
|
|||||||
t.Cleanup(func() { os.Chdir(wd) })
|
t.Cleanup(func() { os.Chdir(wd) })
|
||||||
err := os.Chdir(filepath.Join(wd, "testdata/abraconfig2"))
|
err := os.Chdir(filepath.Join(wd, "testdata/abraconfig2"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := LoadAbraConfig()
|
cfg := LoadAbraConfig()
|
||||||
@ -104,8 +106,9 @@ func TestLoadAbraConfigGetAbraDir(t *testing.T) {
|
|||||||
func TestLoadAbraConfigServersDir(t *testing.T) {
|
func TestLoadAbraConfigServersDir(t *testing.T) {
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Setenv("ABRA_DIR", "")
|
t.Setenv("ABRA_DIR", "")
|
||||||
|
|
||||||
t.Run("default", func(t *testing.T) {
|
t.Run("default", func(t *testing.T) {
|
||||||
@ -120,7 +123,7 @@ func TestLoadAbraConfigServersDir(t *testing.T) {
|
|||||||
t.Cleanup(func() { os.Chdir(wd) })
|
t.Cleanup(func() { os.Chdir(wd) })
|
||||||
err = os.Chdir(filepath.Join(wd, "testdata/abraconfig1"))
|
err = os.Chdir(filepath.Join(wd, "testdata/abraconfig1"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := LoadAbraConfig()
|
cfg := LoadAbraConfig()
|
||||||
|
|||||||
@ -14,8 +14,8 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/recipe"
|
"coopcloud.tech/abra/pkg/recipe"
|
||||||
"coopcloud.tech/abra/pkg/secret"
|
"coopcloud.tech/abra/pkg/secret"
|
||||||
|
|
||||||
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
"github.com/distribution/reference"
|
"github.com/distribution/reference"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
dockerClient "github.com/docker/docker/client"
|
dockerClient "github.com/docker/docker/client"
|
||||||
)
|
)
|
||||||
@ -229,7 +229,7 @@ func GatherSecretsForDeploy(cl *dockerClient.Client, app appPkg.App, showUnchang
|
|||||||
return secretInfo, nil
|
return secretInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GatherConfigsForDeploy(cl *dockerClient.Client, app appPkg.App, compose *composetypes.Config, abraShEnv map[string]string, showUnchanged bool) ([]string, error) {
|
func GatherConfigsForDeploy(cl *dockerClient.Client, app appPkg.App, compose *composeGoTypes.Project, abraShEnv map[string]string, showUnchanged bool) ([]string, error) {
|
||||||
// Get current configs from existing deployment
|
// Get current configs from existing deployment
|
||||||
currentConfigs, err := GetConfigsForStack(cl, app)
|
currentConfigs, err := GetConfigsForStack(cl, app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -268,7 +268,7 @@ func GatherConfigsForDeploy(cl *dockerClient.Client, app appPkg.App, compose *co
|
|||||||
return configInfo, nil
|
return configInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GatherImagesForDeploy(cl *dockerClient.Client, app appPkg.App, compose *composetypes.Config, showUnchanged bool) ([]string, error) {
|
func GatherImagesForDeploy(cl *dockerClient.Client, app appPkg.App, compose *composeGoTypes.Project, showUnchanged bool) ([]string, error) {
|
||||||
// Get current images from existing deployment
|
// Get current images from existing deployment
|
||||||
currentImages, err := GetImagesForStack(cl, app)
|
currentImages, err := GetImagesForStack(cl, app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -10,48 +10,73 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"coopcloud.tech/abra/pkg/envfile"
|
"coopcloud.tech/abra/pkg/envfile"
|
||||||
"coopcloud.tech/abra/pkg/recipe"
|
"coopcloud.tech/abra/pkg/recipe"
|
||||||
testPkg "coopcloud.tech/abra/pkg/test"
|
"coopcloud.tech/abra/pkg/test"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
expectedAppEnv = envfile.AppEnv{
|
||||||
|
"DOMAIN": test.AppName,
|
||||||
|
"RECIPE": test.RecipeName,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedAppFile = appPkg.AppFile{
|
||||||
|
Path: test.AppEnvPath,
|
||||||
|
Server: test.ServerName,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedAppFiles = map[string]appPkg.AppFile{
|
||||||
|
test.AppName: expectedAppFile,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func TestGetAllFoldersInDirectory(t *testing.T) {
|
func TestGetAllFoldersInDirectory(t *testing.T) {
|
||||||
folders, err := config.GetAllFoldersInDirectory(testPkg.TestDir)
|
folders, err := config.GetAllFoldersInDirectory(test.TestDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(folders, testPkg.TFolders) {
|
|
||||||
t.Fatalf("did not get expected folders. Expected: (%s), Got: (%s)", strings.Join(testPkg.TFolders, ","), strings.Join(folders, ","))
|
if !reflect.DeepEqual(folders, test.TFolders) {
|
||||||
|
t.Fatalf("did not get expected folders. Expected: (%s), Got: (%s)", strings.Join(test.TFolders, ","), strings.Join(folders, ","))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAllFilesInDirectory(t *testing.T) {
|
func TestGetAllFilesInDirectory(t *testing.T) {
|
||||||
files, err := config.GetAllFilesInDirectory(testPkg.TestDir)
|
files, err := config.GetAllFilesInDirectory(test.TestDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileNames []string
|
var fileNames []string
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
fileNames = append(fileNames, file.Name())
|
fileNames = append(fileNames, file.Name())
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(fileNames, testPkg.TFiles) {
|
|
||||||
t.Fatalf("did not get expected files. Expected: (%s), Got: (%s)", strings.Join(testPkg.TFiles, ","), strings.Join(fileNames, ","))
|
if !reflect.DeepEqual(fileNames, test.TFiles) {
|
||||||
|
t.Fatalf("did not get expected files. Expected: (%s), Got: (%s)", strings.Join(test.TFiles, ","), strings.Join(fileNames, ","))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadEnv(t *testing.T) {
|
func TestReadEnv(t *testing.T) {
|
||||||
env, err := envfile.ReadEnv(testPkg.ExpectedAppFile.Path)
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
env, err := envfile.ReadEnv(expectedAppFile.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(env, testPkg.ExpectedAppEnv) {
|
|
||||||
|
if !reflect.DeepEqual(env, expectedAppEnv) {
|
||||||
t.Fatal("did not get expected application settings")
|
t.Fatal("did not get expected application settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadAbraShEnvVars(t *testing.T) {
|
func TestReadAbraShEnvVars(t *testing.T) {
|
||||||
r := recipe.Get("abra-test-recipe")
|
test.Setup()
|
||||||
err := r.EnsureExists()
|
t.Cleanup(func() { test.Teardown() })
|
||||||
if err != nil {
|
|
||||||
|
r := recipe.Get(test.AbraTestRecipe)
|
||||||
|
if err := r.EnsureExists(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,9 +103,11 @@ func TestReadAbraShEnvVars(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReadAbraShCmdNames(t *testing.T) {
|
func TestReadAbraShCmdNames(t *testing.T) {
|
||||||
r := recipe.Get("abra-test-recipe")
|
test.Setup()
|
||||||
err := r.EnsureExists()
|
t.Cleanup(func() { test.Teardown() })
|
||||||
if err != nil {
|
|
||||||
|
r := recipe.Get(test.AbraTestRecipe)
|
||||||
|
if err := r.EnsureExists(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,9 +129,11 @@ func TestReadAbraShCmdNames(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckEnv(t *testing.T) {
|
func TestCheckEnv(t *testing.T) {
|
||||||
r := recipe.Get("abra-test-recipe")
|
test.Setup()
|
||||||
err := r.EnsureExists()
|
t.Cleanup(func() { test.Teardown() })
|
||||||
if err != nil {
|
|
||||||
|
r := recipe.Get(test.AbraTestRecipe)
|
||||||
|
if err := r.EnsureExists(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,9 +164,11 @@ func TestCheckEnv(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckEnvError(t *testing.T) {
|
func TestCheckEnvError(t *testing.T) {
|
||||||
r := recipe.Get("abra-test-recipe")
|
test.Setup()
|
||||||
err := r.EnsureExists()
|
t.Cleanup(func() { test.Teardown() })
|
||||||
if err != nil {
|
|
||||||
|
r := recipe.Get(test.AbraTestRecipe)
|
||||||
|
if err := r.EnsureExists(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,9 +201,11 @@ func TestCheckEnvError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEnvVarCommentsRemoved(t *testing.T) {
|
func TestEnvVarCommentsRemoved(t *testing.T) {
|
||||||
r := recipe.Get("abra-test-recipe")
|
test.Setup()
|
||||||
err := r.EnsureExists()
|
t.Cleanup(func() { test.Teardown() })
|
||||||
if err != nil {
|
|
||||||
|
r := recipe.Get(test.AbraTestRecipe)
|
||||||
|
if err := r.EnsureExists(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,9 +234,11 @@ func TestEnvVarCommentsRemoved(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEnvVarModifiersIncluded(t *testing.T) {
|
func TestEnvVarModifiersIncluded(t *testing.T) {
|
||||||
r := recipe.Get("abra-test-recipe")
|
test.Setup()
|
||||||
err := r.EnsureExists()
|
t.Cleanup(func() { test.Teardown() })
|
||||||
if err != nil {
|
|
||||||
|
r := recipe.Get(test.AbraTestRecipe)
|
||||||
|
if err := r.EnsureExists(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +260,10 @@ func TestEnvVarModifiersIncluded(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNoOverwriteNonVersionEnvVars(t *testing.T) {
|
func TestNoOverwriteNonVersionEnvVars(t *testing.T) {
|
||||||
app, err := appPkg.GetApp(testPkg.ExpectedAppFiles, testPkg.AppName)
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
app, err := appPkg.GetApp(expectedAppFiles, test.AppName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -234,7 +272,7 @@ func TestNoOverwriteNonVersionEnvVars(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app, err = appPkg.GetApp(testPkg.ExpectedAppFiles, testPkg.AppName)
|
app, err = appPkg.GetApp(expectedAppFiles, test.AppName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,11 +8,44 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
|
"coopcloud.tech/abra/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
teardown()
|
||||||
|
|
||||||
|
if err := os.Mkdir(os.ExpandEnv("$ABRA_DIR"), 0764); err != nil {
|
||||||
|
if !os.IsExist(err) {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Mkdir(os.ExpandEnv("$ABRA_DIR/recipes"), 0764); err != nil {
|
||||||
|
if !os.IsExist(err) {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func teardown() {
|
||||||
|
abraDir := os.ExpandEnv("$ABRA_DIR")
|
||||||
|
if abraDir == fmt.Sprintf("%s/.abra", os.ExpandEnv("$HOME")) {
|
||||||
|
log.Fatal("set $ABRA_DIR before running the test suite")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.RemoveAll(abraDir); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestClone(t *testing.T) {
|
func TestClone(t *testing.T) {
|
||||||
|
setup()
|
||||||
|
t.Cleanup(func() { teardown() })
|
||||||
|
|
||||||
dir := path.Join(config.RECIPES_DIR, "gitea")
|
dir := path.Join(config.RECIPES_DIR, "gitea")
|
||||||
os.RemoveAll(dir)
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
gitURL := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, "gitea")
|
gitURL := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, "gitea")
|
||||||
if err := Clone(dir, gitURL); err != nil {
|
if err := Clone(dir, gitURL); err != nil {
|
||||||
@ -25,6 +58,11 @@ func TestClone(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCancelGitClone(t *testing.T) {
|
func TestCancelGitClone(t *testing.T) {
|
||||||
|
t.Skip("https://git.coopcloud.tech/toolshed/abra/issues/814")
|
||||||
|
|
||||||
|
setup()
|
||||||
|
t.Cleanup(func() { teardown() })
|
||||||
|
|
||||||
dir := path.Join(config.RECIPES_DIR, "gitea")
|
dir := path.Join(config.RECIPES_DIR, "gitea")
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -62,13 +62,6 @@ func (l LintRule) Skip(recipe recipe.Recipe) bool {
|
|||||||
|
|
||||||
var LintRules = map[string][]LintRule{
|
var LintRules = map[string][]LintRule{
|
||||||
"warn": {
|
"warn": {
|
||||||
{
|
|
||||||
Ref: "R001",
|
|
||||||
Level: i18n.G("warn"),
|
|
||||||
Description: i18n.G("compose config has expected version"),
|
|
||||||
HowToResolve: i18n.G("ensure 'version: \"3.8\"' in compose configs"),
|
|
||||||
Function: LintComposeVersion,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Ref: "R002",
|
Ref: "R002",
|
||||||
Level: i18n.G("warn"),
|
Level: i18n.G("warn"),
|
||||||
@ -217,18 +210,6 @@ func LintForErrors(recipe recipe.Recipe) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func LintComposeVersion(recipe recipe.Recipe) (bool, error) {
|
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if config.Version == "3.8" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LintEnvConfigPresent(r recipe.Recipe) (bool, error) {
|
func LintEnvConfigPresent(r recipe.Recipe) (bool, error) {
|
||||||
if _, err := os.Stat(r.SampleEnvPath); !os.IsNotExist(err) {
|
if _, err := os.Stat(r.SampleEnvPath); !os.IsNotExist(err) {
|
||||||
return true, nil
|
return true, nil
|
||||||
@ -238,7 +219,7 @@ func LintEnvConfigPresent(r recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintAppService(recipe recipe.Recipe) (bool, error) {
|
func LintAppService(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -269,7 +250,7 @@ func LintTraefikEnabledSkipCondition(r recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintTraefikEnabled(recipe recipe.Recipe) (bool, error) {
|
func LintTraefikEnabled(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -287,7 +268,7 @@ func LintTraefikEnabled(recipe recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintDeployLabelsPresent(recipe recipe.Recipe) (bool, error) {
|
func LintDeployLabelsPresent(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -302,7 +283,7 @@ func LintDeployLabelsPresent(recipe recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintHealthchecks(recipe recipe.Recipe) (bool, error) {
|
func LintHealthchecks(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -316,7 +297,7 @@ func LintHealthchecks(recipe recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintAllImagesTagged(recipe recipe.Recipe) (bool, error) {
|
func LintAllImagesTagged(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -334,7 +315,7 @@ func LintAllImagesTagged(recipe recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintNoUnstableTags(recipe recipe.Recipe) (bool, error) {
|
func LintNoUnstableTags(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -361,7 +342,7 @@ func LintNoUnstableTags(recipe recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintSemverLikeTags(recipe recipe.Recipe) (bool, error) {
|
func LintSemverLikeTags(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -388,7 +369,7 @@ func LintSemverLikeTags(recipe recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintImagePresent(recipe recipe.Recipe) (bool, error) {
|
func LintImagePresent(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -440,7 +421,7 @@ func LintMetadataFilledIn(r recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintAbraShVendors(recipe recipe.Recipe) (bool, error) {
|
func LintAbraShVendors(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -472,7 +453,7 @@ func LintHasRecipeRepo(recipe recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintSecretLengths(recipe recipe.Recipe) (bool, error) {
|
func LintSecretLengths(recipe recipe.Recipe) (bool, error) {
|
||||||
config, err := recipe.GetComposeConfig(nil)
|
config, err := recipe.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,10 +11,9 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/formatter"
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
"coopcloud.tech/abra/pkg/i18n"
|
"coopcloud.tech/abra/pkg/i18n"
|
||||||
"coopcloud.tech/abra/pkg/log"
|
"coopcloud.tech/abra/pkg/log"
|
||||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
|
||||||
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
"github.com/distribution/reference"
|
"github.com/distribution/reference"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetComposeFiles gets the list of compose files for an app (or recipe if you
|
// GetComposeFiles gets the list of compose files for an app (or recipe if you
|
||||||
@ -61,7 +60,7 @@ func (r Recipe) GetComposeFiles(appEnv map[string]string) ([]string, error) {
|
|||||||
return composeFiles, nil
|
return composeFiles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Recipe) GetComposeConfig(env map[string]string) (*composetypes.Config, error) {
|
func (r Recipe) GetComposeConfig() (*composeGoTypes.Project, error) {
|
||||||
pattern := fmt.Sprintf("%s/compose**yml", r.Dir)
|
pattern := fmt.Sprintf("%s/compose**yml", r.Dir)
|
||||||
composeFiles, err := filepath.Glob(pattern)
|
composeFiles, err := filepath.Glob(pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -72,25 +71,18 @@ func (r Recipe) GetComposeConfig(env map[string]string) (*composetypes.Config, e
|
|||||||
return nil, errors.New(i18n.G("%s is missing a compose.yml or compose.*.yml file?", r.Name))
|
return nil, errors.New(i18n.G("%s is missing a compose.yml or compose.*.yml file?", r.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
if env == nil {
|
config, err := loader.LoadCompose(loader.LoadConf{ComposeFiles: composeFiles})
|
||||||
env, err = r.SampleEnv()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := stack.Deploy{Composefiles: composeFiles}
|
|
||||||
config, err := loader.LoadComposefile(opts, env)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVersionLabelLocal retrieves the version label on the local recipe config
|
// GetVersionLabelLocal retrieves the version label on the local recipe config
|
||||||
func (r Recipe) GetVersionLabelLocal() (string, error) {
|
func (r Recipe) GetVersionLabelLocal() (string, error) {
|
||||||
var label string
|
var label string
|
||||||
config, err := r.GetComposeConfig(nil)
|
config, err := r.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -123,14 +115,7 @@ func (r Recipe) UpdateTag(image, tag string) (bool, error) {
|
|||||||
log.Debug(i18n.G("considering %s config(s) for tag update", strings.Join(composeFiles, ", ")))
|
log.Debug(i18n.G("considering %s config(s) for tag update", strings.Join(composeFiles, ", ")))
|
||||||
|
|
||||||
for _, composeFile := range composeFiles {
|
for _, composeFile := range composeFiles {
|
||||||
opts := stack.Deploy{Composefiles: []string{composeFile}}
|
compose, err := loader.LoadCompose(loader.LoadConf{ComposeFiles: []string{composeFile}})
|
||||||
|
|
||||||
sampleEnv, err := r.SampleEnv()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
compose, err := loader.LoadComposefile(opts, sampleEnv)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -168,9 +153,9 @@ func (r Recipe) UpdateTag(image, tag string) (bool, error) {
|
|||||||
new := fmt.Sprintf("%s:%s", composeImage, tag)
|
new := fmt.Sprintf("%s:%s", composeImage, tag)
|
||||||
replacedBytes := strings.Replace(string(bytes), old, new, -1)
|
replacedBytes := strings.Replace(string(bytes), old, new, -1)
|
||||||
|
|
||||||
log.Debug(i18n.G("updating %s to %s in %s", old, new, compose.Filename))
|
log.Debug(i18n.G("updating %s to %s in %s", old, new, compose.Name))
|
||||||
|
|
||||||
if err := os.WriteFile(compose.Filename, []byte(replacedBytes), 0o764); err != nil {
|
if err := os.WriteFile(compose.Name, []byte(replacedBytes), 0o764); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,20 +176,13 @@ func (r Recipe) UpdateLabel(pattern, serviceName, label string) error {
|
|||||||
log.Debug(i18n.G("considering %s config(s) for label update", strings.Join(composeFiles, ", ")))
|
log.Debug(i18n.G("considering %s config(s) for label update", strings.Join(composeFiles, ", ")))
|
||||||
|
|
||||||
for _, composeFile := range composeFiles {
|
for _, composeFile := range composeFiles {
|
||||||
opts := stack.Deploy{Composefiles: []string{composeFile}}
|
compose, err := loader.LoadCompose(loader.LoadConf{ComposeFiles: []string{composeFile}})
|
||||||
|
|
||||||
sampleEnv, err := r.SampleEnv()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
compose, err := loader.LoadComposefile(opts, sampleEnv)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceExists := false
|
serviceExists := false
|
||||||
var service composetypes.ServiceConfig
|
var service composeGoTypes.ServiceConfig
|
||||||
for _, s := range compose.Services {
|
for _, s := range compose.Services {
|
||||||
if s.Name == serviceName {
|
if s.Name == serviceName {
|
||||||
service = s
|
service = s
|
||||||
@ -234,9 +212,9 @@ func (r Recipe) UpdateLabel(pattern, serviceName, label string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug(i18n.G("updating %s to %s in %s", old, label, compose.Filename))
|
log.Debug(i18n.G("updating %s to %s in %s", old, label, compose.Name))
|
||||||
|
|
||||||
if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0o764); err != nil {
|
if err := ioutil.WriteFile(compose.Name, []byte(replacedBytes), 0o764); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -416,7 +416,7 @@ func (r Recipe) GetRecipeVersions() (RecipeVersions, []string, error) {
|
|||||||
|
|
||||||
log.Debug(i18n.G("git checkout: %s in %s", ref.Name(), r.Dir))
|
log.Debug(i18n.G("git checkout: %s in %s", ref.Name(), r.Dir))
|
||||||
|
|
||||||
config, err := r.GetComposeConfig(nil)
|
config, err := r.GetComposeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(i18n.G("failed to get compose config for %s: %s", tag, err))
|
log.Debug(i18n.G("failed to get compose config for %s: %s", tag, err))
|
||||||
warnMsg = append(warnMsg, i18n.G("skipping tag %s: invalid compose config: %s", tag, err))
|
warnMsg = append(warnMsg, i18n.G("skipping tag %s: invalid compose config: %s", tag, err))
|
||||||
|
|||||||
@ -5,12 +5,15 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"coopcloud.tech/abra/pkg/test"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIsDirty(t *testing.T) {
|
func TestIsDirty(t *testing.T) {
|
||||||
r := Get("abra-test-recipe")
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
r := Get(test.RecipeName)
|
||||||
if err := r.EnsureExists(); err != nil {
|
if err := r.EnsureExists(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -22,10 +25,9 @@ func TestIsDirty(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
defer t.Cleanup(func() {
|
t.Cleanup(func() { os.Remove(fpath) })
|
||||||
os.Remove(fpath)
|
|
||||||
})
|
|
||||||
|
|
||||||
dirty, err := r.IsDirty()
|
dirty, err := r.IsDirty()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
|
"coopcloud.tech/abra/pkg/test"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -101,24 +102,24 @@ func TestGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetVersionLabelLocalDoesNotUseTimeoutLabel(t *testing.T) {
|
func TestGetVersionLabelLocalDoesNotUseTimeoutLabel(t *testing.T) {
|
||||||
r := Get("traefik")
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
r := Get(test.RecipeName)
|
||||||
if err := r.EnsureExists(); err != nil {
|
if err := r.EnsureExists(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 1; i < 50; i++ {
|
timeout := "120"
|
||||||
|
if err := test.AddEnv("TIMEOUT", timeout); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < 3; i++ {
|
||||||
label, err := r.GetVersionLabelLocal()
|
label, err := r.GetVersionLabelLocal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
assert.NotEqual(t, label, timeout)
|
||||||
// NOTE(d1): this is potentially quite a brittle unit test as it needs to
|
|
||||||
// hardcode the default timeout label to ensure that the label parser never
|
|
||||||
// returns it. hopefully this won't fail too often! if you're here because
|
|
||||||
// of a failure, just update the `defaultTimeoutLabel` value & permalink
|
|
||||||
// below
|
|
||||||
// https://git.coopcloud.tech/coop-cloud/traefik/src/commit/ac3a47fe8ca3ef92db84f64cfedfbb348000faee/.env.sample#L2
|
|
||||||
defaultTimeoutLabel := "300"
|
|
||||||
assert.NotEqual(t, label, defaultTimeoutLabel)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/envfile"
|
"coopcloud.tech/abra/pkg/envfile"
|
||||||
"coopcloud.tech/abra/pkg/i18n"
|
"coopcloud.tech/abra/pkg/i18n"
|
||||||
"coopcloud.tech/abra/pkg/log"
|
"coopcloud.tech/abra/pkg/log"
|
||||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
|
||||||
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
"github.com/decentral1se/passgen"
|
"github.com/decentral1se/passgen"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
@ -122,14 +121,13 @@ func ReadSecretsConfig(appEnvPath string, composeFiles []string, stackName strin
|
|||||||
// Set the STACK_NAME to be able to generate the remote name correctly.
|
// Set the STACK_NAME to be able to generate the remote name correctly.
|
||||||
appEnv["STACK_NAME"] = stackName
|
appEnv["STACK_NAME"] = stackName
|
||||||
|
|
||||||
opts := stack.Deploy{Composefiles: composeFiles}
|
composeConfig, err := loader.LoadCompose(loader.LoadConf{ComposeFiles: composeFiles, AppEnv: appEnv})
|
||||||
composeConfig, err := loader.LoadComposefile(opts, appEnv)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the compose files without injecting environment variables.
|
// Read the compose files without injecting environment variables.
|
||||||
configWithoutEnv, err := loader.LoadComposefile(opts, map[string]string{}, loader.SkipInterpolation)
|
configWithoutEnv, err := loader.LoadCompose(loader.LoadConf{ComposeFiles: composeFiles})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
103
pkg/test/test.go
103
pkg/test/test.go
@ -2,57 +2,53 @@ package test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
appPkg "coopcloud.tech/abra/pkg/app"
|
gitPkg "coopcloud.tech/abra/pkg/git"
|
||||||
"coopcloud.tech/abra/pkg/envfile"
|
"git.coopcloud.tech/toolshed/godotenv"
|
||||||
"coopcloud.tech/abra/pkg/log"
|
|
||||||
"coopcloud.tech/abra/pkg/recipe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
AppName = "test_app.example.com"
|
AppName = "test_app.example.com"
|
||||||
|
StackName = "test_app_example_com"
|
||||||
ServerName = "test_server"
|
ServerName = "test_server"
|
||||||
TFiles = []string{"bar.env", "foo.env"}
|
RecipeName = "test_recipe"
|
||||||
TFolders = []string{"dir1", "dir2"}
|
|
||||||
TestServer = os.ExpandEnv("$PWD/../../tests/resources/test_server")
|
|
||||||
TestDir = os.ExpandEnv("$PWD/../../tests/resources/test_dir")
|
|
||||||
|
|
||||||
ExpectedAppEnv = envfile.AppEnv{
|
TFiles = []string{"bar.env", "foo.env"}
|
||||||
"DOMAIN": "test_app.example.com",
|
TFolders = []string{"dir1", "dir2"}
|
||||||
"RECIPE": "test_recipe",
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpectedApp = appPkg.App{
|
ServerDir = os.ExpandEnv("$ABRA_DIR/servers/test_server")
|
||||||
Name: AppName,
|
RecipeDir = os.ExpandEnv("$ABRA_DIR/recipes/test_recipe")
|
||||||
Recipe: recipe.Get(ExpectedAppEnv["RECIPE"]),
|
TestDir = os.ExpandEnv("$PWD/../../tests/resources/test_dir")
|
||||||
Domain: ExpectedAppEnv["DOMAIN"],
|
|
||||||
Env: ExpectedAppEnv,
|
|
||||||
Path: ExpectedAppFile.Path,
|
|
||||||
Server: ExpectedAppFile.Server,
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpectedAppFile = appPkg.AppFile{
|
AppEnvPath = path.Join(ServerDir, fmt.Sprintf("%s.env", AppName))
|
||||||
Path: path.Join(TestServer, fmt.Sprintf("%s.env", AppName)),
|
|
||||||
Server: ServerName,
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpectedAppFiles = map[string]appPkg.AppFile{
|
AbraTestRecipe = "abra-test-recipe"
|
||||||
AppName: ExpectedAppFile,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func RmServerAppRecipe() {
|
func Teardown() {
|
||||||
testAppLink := os.ExpandEnv("$ABRA_DIR/servers/test_server")
|
abraDir := os.ExpandEnv("$ABRA_DIR")
|
||||||
os.Remove(testAppLink)
|
if abraDir == fmt.Sprintf("%s/.abra", os.ExpandEnv("$HOME")) {
|
||||||
|
log.Fatal("set $ABRA_DIR before running the test suite")
|
||||||
|
}
|
||||||
|
|
||||||
testRecipeLink := os.ExpandEnv("$ABRA_DIR/recipes/test_recipe")
|
if err := os.RemoveAll(abraDir); err != nil {
|
||||||
os.Remove(testRecipeLink)
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func MkServerAppRecipe() {
|
func Setup() {
|
||||||
RmServerAppRecipe()
|
Teardown()
|
||||||
|
|
||||||
|
if err := os.Mkdir(os.ExpandEnv("$ABRA_DIR"), 0764); err != nil {
|
||||||
|
if !os.IsExist(err) {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := os.Mkdir(os.ExpandEnv("$ABRA_DIR/servers"), 0700); err != nil {
|
if err := os.Mkdir(os.ExpandEnv("$ABRA_DIR/servers"), 0700); err != nil {
|
||||||
if !os.IsExist(err) {
|
if !os.IsExist(err) {
|
||||||
@ -66,15 +62,42 @@ func MkServerAppRecipe() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
testAppDir := os.ExpandEnv("$PWD/../../tests/resources/test_server")
|
_, f, _, ok := runtime.Caller(0)
|
||||||
testAppLink := os.ExpandEnv("$ABRA_DIR/servers/test_server")
|
if !ok {
|
||||||
if err := os.Symlink(testAppDir, testAppLink); err != nil {
|
log.Fatal("Setup: unable to discover current working directory of file")
|
||||||
|
}
|
||||||
|
pwd := filepath.Dir(f)
|
||||||
|
|
||||||
|
serverSrcDir := filepath.Join(pwd, "/../../tests/resources/test_server")
|
||||||
|
serverDestDir := os.ExpandEnv("$ABRA_DIR/servers/test_server")
|
||||||
|
if err := os.CopyFS(serverDestDir, os.DirFS(serverSrcDir)); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
testRecipeDir := os.ExpandEnv("$PWD/../../tests/resources/test_recipe")
|
recipeSrcDir := filepath.Join(pwd, "/../../tests/resources/test_recipe")
|
||||||
testRecipeLink := os.ExpandEnv("$ABRA_DIR/recipes/test_recipe")
|
recipeDestDir := os.ExpandEnv("$ABRA_DIR/recipes/test_recipe")
|
||||||
if err := os.Symlink(testRecipeDir, testRecipeLink); err != nil {
|
if err := os.CopyFS(recipeDestDir, os.DirFS(recipeSrcDir)); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gitPkg.Init(recipeDestDir, true, "tester", "helo@coopcloud.tech"); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddEnv(envKey, envValue string) error {
|
||||||
|
filePath := os.ExpandEnv(fmt.Sprintf("$ABRA_DIR/servers/%s/%s.env", ServerName, AppName))
|
||||||
|
|
||||||
|
envVars, _, err := godotenv.Read(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
envVars[envKey] = envValue
|
||||||
|
|
||||||
|
if err := godotenv.Write(envVars, filePath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
networktypes "github.com/docker/docker/api/types/network"
|
networktypes "github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
)
|
)
|
||||||
@ -48,19 +48,17 @@ func AddStackLabel(namespace Namespace, labels map[string]string) map[string]str
|
|||||||
return labels
|
return labels
|
||||||
}
|
}
|
||||||
|
|
||||||
type networkMap map[string]composetypes.NetworkConfig
|
|
||||||
|
|
||||||
// Networks from the compose-file type to the engine API type
|
// Networks from the compose-file type to the engine API type
|
||||||
func Networks(namespace Namespace, networks networkMap, servicesNetworks map[string]struct{}) (map[string]networktypes.CreateOptions, []string) {
|
func Networks(namespace Namespace, networks map[string]composeGoTypes.NetworkConfig, servicesNetworks map[string]struct{}) (map[string]networktypes.CreateOptions, []string) {
|
||||||
if networks == nil {
|
if networks == nil {
|
||||||
networks = make(map[string]composetypes.NetworkConfig)
|
networks = make(map[string]composeGoTypes.NetworkConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
externalNetworks := []string{}
|
externalNetworks := []string{}
|
||||||
result := make(map[string]networktypes.CreateOptions)
|
result := make(map[string]networktypes.CreateOptions)
|
||||||
for internalName := range servicesNetworks {
|
for internalName := range servicesNetworks {
|
||||||
network := networks[internalName]
|
network := networks[internalName]
|
||||||
if network.External.External {
|
if network.External {
|
||||||
externalNetworks = append(externalNetworks, network.Name)
|
externalNetworks = append(externalNetworks, network.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -98,19 +96,19 @@ func Networks(namespace Namespace, networks networkMap, servicesNetworks map[str
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Secrets converts secrets from the Compose type to the engine API type
|
// Secrets converts secrets from the Compose type to the engine API type
|
||||||
func Secrets(namespace Namespace, secrets map[string]composetypes.SecretConfig) ([]swarm.SecretSpec, error) {
|
func Secrets(namespace Namespace, secrets map[string]composeGoTypes.SecretConfig) ([]swarm.SecretSpec, error) {
|
||||||
result := []swarm.SecretSpec{}
|
result := []swarm.SecretSpec{}
|
||||||
for name, secret := range secrets {
|
for name, secret := range secrets {
|
||||||
if secret.External.External {
|
if secret.External {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var obj swarmFileObject
|
var obj swarmFileObject
|
||||||
var err error
|
var err error
|
||||||
if secret.Driver != "" {
|
if secret.Driver != "" {
|
||||||
obj = driverObjectConfig(namespace, name, composetypes.FileObjectConfig(secret))
|
obj = driverObjectConfig(namespace, name, composeGoTypes.FileObjectConfig(secret))
|
||||||
} else {
|
} else {
|
||||||
obj, err = fileObjectConfig(namespace, name, composetypes.FileObjectConfig(secret))
|
obj, err = fileObjectConfig(namespace, name, composeGoTypes.FileObjectConfig(secret))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -133,14 +131,14 @@ func Secrets(namespace Namespace, secrets map[string]composetypes.SecretConfig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configs converts config objects from the Compose type to the engine API type
|
// Configs converts config objects from the Compose type to the engine API type
|
||||||
func Configs(namespace Namespace, configs map[string]composetypes.ConfigObjConfig) ([]swarm.ConfigSpec, error) {
|
func Configs(namespace Namespace, configs map[string]composeGoTypes.ConfigObjConfig) ([]swarm.ConfigSpec, error) {
|
||||||
result := []swarm.ConfigSpec{}
|
result := []swarm.ConfigSpec{}
|
||||||
for name, config := range configs {
|
for name, config := range configs {
|
||||||
if config.External.External {
|
if config.External {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := fileObjectConfig(namespace, name, composetypes.FileObjectConfig(config))
|
obj, err := fileObjectConfig(namespace, name, composeGoTypes.FileObjectConfig(config))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -160,7 +158,7 @@ type swarmFileObject struct {
|
|||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func driverObjectConfig(namespace Namespace, name string, obj composetypes.FileObjectConfig) swarmFileObject {
|
func driverObjectConfig(namespace Namespace, name string, obj composeGoTypes.FileObjectConfig) swarmFileObject {
|
||||||
if obj.Name != "" {
|
if obj.Name != "" {
|
||||||
name = obj.Name
|
name = obj.Name
|
||||||
} else {
|
} else {
|
||||||
@ -176,7 +174,7 @@ func driverObjectConfig(namespace Namespace, name string, obj composetypes.FileO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fileObjectConfig(namespace Namespace, name string, obj composetypes.FileObjectConfig) (swarmFileObject, error) {
|
func fileObjectConfig(namespace Namespace, name string, obj composeGoTypes.FileObjectConfig) (swarmFileObject, error) {
|
||||||
data, err := ioutil.ReadFile(obj.File)
|
data, err := ioutil.ReadFile(obj.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return swarmFileObject{}, err
|
return swarmFileObject{}, err
|
||||||
|
|||||||
@ -1,170 +0,0 @@
|
|||||||
package convert // https://github.com/docker/cli/blob/master/cli/compose/convert/compose_test.go
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
|
||||||
"github.com/docker/docker/api/types/network"
|
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
"gotest.tools/v3/fs"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNamespaceScope(t *testing.T) {
|
|
||||||
scoped := Namespace{name: "foo"}.Scope("bar")
|
|
||||||
assert.Check(t, is.Equal("foo_bar", scoped))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddStackLabel(t *testing.T) {
|
|
||||||
labels := map[string]string{
|
|
||||||
"something": "labeled",
|
|
||||||
}
|
|
||||||
actual := AddStackLabel(Namespace{name: "foo"}, labels)
|
|
||||||
expected := map[string]string{
|
|
||||||
"something": "labeled",
|
|
||||||
LabelNamespace: "foo",
|
|
||||||
}
|
|
||||||
assert.Check(t, is.DeepEqual(expected, actual))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNetworks(t *testing.T) {
|
|
||||||
namespace := Namespace{name: "foo"}
|
|
||||||
serviceNetworks := map[string]struct{}{
|
|
||||||
"normal": {},
|
|
||||||
"outside": {},
|
|
||||||
"default": {},
|
|
||||||
"attachablenet": {},
|
|
||||||
"named": {},
|
|
||||||
}
|
|
||||||
source := networkMap{
|
|
||||||
"normal": composetypes.NetworkConfig{
|
|
||||||
Driver: "overlay",
|
|
||||||
DriverOpts: map[string]string{
|
|
||||||
"opt": "value",
|
|
||||||
},
|
|
||||||
Ipam: composetypes.IPAMConfig{
|
|
||||||
Driver: "driver",
|
|
||||||
Config: []*composetypes.IPAMPool{
|
|
||||||
{
|
|
||||||
Subnet: "10.0.0.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Labels: map[string]string{
|
|
||||||
"something": "labeled",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"outside": composetypes.NetworkConfig{
|
|
||||||
External: composetypes.External{External: true},
|
|
||||||
Name: "special",
|
|
||||||
},
|
|
||||||
"attachablenet": composetypes.NetworkConfig{
|
|
||||||
Driver: "overlay",
|
|
||||||
Attachable: true,
|
|
||||||
},
|
|
||||||
"named": composetypes.NetworkConfig{
|
|
||||||
Name: "othername",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
expected := map[string]network.CreateOptions{
|
|
||||||
"foo_default": {
|
|
||||||
Labels: map[string]string{
|
|
||||||
LabelNamespace: "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"foo_normal": {
|
|
||||||
Driver: "overlay",
|
|
||||||
IPAM: &network.IPAM{
|
|
||||||
Driver: "driver",
|
|
||||||
Config: []network.IPAMConfig{
|
|
||||||
{
|
|
||||||
Subnet: "10.0.0.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Options: map[string]string{
|
|
||||||
"opt": "value",
|
|
||||||
},
|
|
||||||
Labels: map[string]string{
|
|
||||||
LabelNamespace: "foo",
|
|
||||||
"something": "labeled",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"foo_attachablenet": {
|
|
||||||
Driver: "overlay",
|
|
||||||
Attachable: true,
|
|
||||||
Labels: map[string]string{
|
|
||||||
LabelNamespace: "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"othername": {
|
|
||||||
Labels: map[string]string{LabelNamespace: "foo"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
networks, externals := Networks(namespace, source, serviceNetworks)
|
|
||||||
assert.DeepEqual(t, expected, networks)
|
|
||||||
assert.DeepEqual(t, []string{"special"}, externals)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSecrets(t *testing.T) {
|
|
||||||
namespace := Namespace{name: "foo"}
|
|
||||||
|
|
||||||
secretText := "this is the first secret"
|
|
||||||
secretFile := fs.NewFile(t, "convert-secrets", fs.WithContent(secretText))
|
|
||||||
defer secretFile.Remove()
|
|
||||||
|
|
||||||
source := map[string]composetypes.SecretConfig{
|
|
||||||
"one": {
|
|
||||||
File: secretFile.Path(),
|
|
||||||
Labels: map[string]string{"monster": "mash"},
|
|
||||||
},
|
|
||||||
"ext": {
|
|
||||||
External: composetypes.External{
|
|
||||||
External: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
specs, err := Secrets(namespace, source)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Assert(t, is.Len(specs, 1))
|
|
||||||
secret := specs[0]
|
|
||||||
assert.Check(t, is.Equal("foo_one", secret.Name))
|
|
||||||
assert.Check(t, is.DeepEqual(map[string]string{
|
|
||||||
"monster": "mash",
|
|
||||||
LabelNamespace: "foo",
|
|
||||||
}, secret.Labels))
|
|
||||||
assert.Check(t, is.DeepEqual([]byte(secretText), secret.Data))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConfigs(t *testing.T) {
|
|
||||||
namespace := Namespace{name: "foo"}
|
|
||||||
|
|
||||||
configText := "this is the first config"
|
|
||||||
configFile := fs.NewFile(t, "convert-configs", fs.WithContent(configText))
|
|
||||||
defer configFile.Remove()
|
|
||||||
|
|
||||||
source := map[string]composetypes.ConfigObjConfig{
|
|
||||||
"one": {
|
|
||||||
File: configFile.Path(),
|
|
||||||
Labels: map[string]string{"monster": "mash"},
|
|
||||||
},
|
|
||||||
"ext": {
|
|
||||||
External: composetypes.External{
|
|
||||||
External: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
specs, err := Configs(namespace, source)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Assert(t, is.Len(specs, 1))
|
|
||||||
config := specs[0]
|
|
||||||
assert.Check(t, is.Equal("foo_one", config.Name))
|
|
||||||
assert.Check(t, is.DeepEqual(map[string]string{
|
|
||||||
"monster": "mash",
|
|
||||||
LabelNamespace: "foo",
|
|
||||||
}, config.Labels))
|
|
||||||
assert.Check(t, is.DeepEqual([]byte(configText), config.Data))
|
|
||||||
}
|
|
||||||
@ -5,11 +5,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"coopcloud.tech/abra/pkg/i18n"
|
"coopcloud.tech/abra/pkg/i18n"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
"github.com/docker/cli/opts"
|
"github.com/docker/cli/opts"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
@ -178,7 +180,7 @@ func ParseConfigs(client client.ConfigAPIClient, requestedConfigs []*swarmtypes.
|
|||||||
// Services from compose-file types to engine API types
|
// Services from compose-file types to engine API types
|
||||||
func Services(
|
func Services(
|
||||||
namespace Namespace,
|
namespace Namespace,
|
||||||
config *composetypes.Config,
|
config *composeGoTypes.Project,
|
||||||
client client.CommonAPIClient,
|
client client.CommonAPIClient,
|
||||||
) (map[string]swarm.ServiceSpec, error) {
|
) (map[string]swarm.ServiceSpec, error) {
|
||||||
result := make(map[string]swarm.ServiceSpec)
|
result := make(map[string]swarm.ServiceSpec)
|
||||||
@ -211,14 +213,17 @@ func Services(
|
|||||||
func Service(
|
func Service(
|
||||||
apiVersion string,
|
apiVersion string,
|
||||||
namespace Namespace,
|
namespace Namespace,
|
||||||
service composetypes.ServiceConfig,
|
service composeGoTypes.ServiceConfig,
|
||||||
networkConfigs map[string]composetypes.NetworkConfig,
|
networkConfigs map[string]composeGoTypes.NetworkConfig,
|
||||||
volumes map[string]composetypes.VolumeConfig,
|
volumes map[string]composeGoTypes.VolumeConfig,
|
||||||
secrets []*swarm.SecretReference,
|
secrets []*swarm.SecretReference,
|
||||||
configs []*swarm.ConfigReference,
|
configs []*swarm.ConfigReference,
|
||||||
) (swarm.ServiceSpec, error) {
|
) (swarm.ServiceSpec, error) {
|
||||||
name := namespace.Scope(service.Name)
|
name := namespace.Scope(service.Name)
|
||||||
endpoint := convertEndpointSpec(service.Deploy.EndpointMode, service.Ports)
|
endpoint, err := convertEndpointSpec(service.Deploy.EndpointMode, service.Ports)
|
||||||
|
if err != nil {
|
||||||
|
return swarm.ServiceSpec{}, err
|
||||||
|
}
|
||||||
|
|
||||||
mode, err := convertDeployMode(service.Deploy.Mode, service.Deploy.Replicas)
|
mode, err := convertDeployMode(service.Deploy.Mode, service.Deploy.Replicas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -254,9 +259,16 @@ func Service(
|
|||||||
dnsConfig := convertDNSConfig(service.DNS, service.DNSSearch)
|
dnsConfig := convertDNSConfig(service.DNS, service.DNSSearch)
|
||||||
|
|
||||||
var privileges swarm.Privileges
|
var privileges swarm.Privileges
|
||||||
|
|
||||||
|
credSpec := service.CredentialSpec
|
||||||
|
if credSpec == nil {
|
||||||
|
credSpec = &composeGoTypes.CredentialSpecConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
privileges.CredentialSpec, err = convertCredentialSpec(
|
privileges.CredentialSpec, err = convertCredentialSpec(
|
||||||
namespace, service.CredentialSpec, configs,
|
namespace, *credSpec, configs,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return swarm.ServiceSpec{}, err
|
return swarm.ServiceSpec{}, err
|
||||||
}
|
}
|
||||||
@ -271,6 +283,11 @@ func Service(
|
|||||||
|
|
||||||
capAdd, capDrop := opts.EffectiveCapAddCapDrop(service.CapAdd, service.CapDrop)
|
capAdd, capDrop := opts.EffectiveCapAddCapDrop(service.CapAdd, service.CapDrop)
|
||||||
|
|
||||||
|
var stopGracePtr time.Duration
|
||||||
|
if service.StopGracePeriod != nil {
|
||||||
|
stopGracePtr = time.Duration(*service.StopGracePeriod)
|
||||||
|
}
|
||||||
|
|
||||||
serviceSpec := swarm.ServiceSpec{
|
serviceSpec := swarm.ServiceSpec{
|
||||||
Annotations: swarm.Annotations{
|
Annotations: swarm.Annotations{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -290,7 +307,7 @@ func Service(
|
|||||||
Dir: service.WorkingDir,
|
Dir: service.WorkingDir,
|
||||||
User: service.User,
|
User: service.User,
|
||||||
Mounts: mounts,
|
Mounts: mounts,
|
||||||
StopGracePeriod: composetypes.ConvertDurationPtr(service.StopGracePeriod),
|
StopGracePeriod: &stopGracePtr,
|
||||||
StopSignal: service.StopSignal,
|
StopSignal: service.StopSignal,
|
||||||
TTY: service.Tty,
|
TTY: service.Tty,
|
||||||
OpenStdin: service.StdinOpen,
|
OpenStdin: service.StdinOpen,
|
||||||
@ -338,7 +355,7 @@ func Service(
|
|||||||
return serviceSpec, nil
|
return serviceSpec, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPlacementPreference(preferences []composetypes.PlacementPreferences) []swarm.PlacementPreference {
|
func getPlacementPreference(preferences []composeGoTypes.PlacementPreferences) []swarm.PlacementPreference {
|
||||||
result := []swarm.PlacementPreference{}
|
result := []swarm.PlacementPreference{}
|
||||||
for _, preference := range preferences {
|
for _, preference := range preferences {
|
||||||
spreadDescriptor := preference.Spread
|
spreadDescriptor := preference.Spread
|
||||||
@ -357,13 +374,13 @@ func sortStrings(strs []string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func convertServiceNetworks(
|
func convertServiceNetworks(
|
||||||
networks map[string]*composetypes.ServiceNetworkConfig,
|
networks map[string]*composeGoTypes.ServiceNetworkConfig,
|
||||||
networkConfigs networkMap,
|
networkConfigs map[string]composeGoTypes.NetworkConfig,
|
||||||
namespace Namespace,
|
namespace Namespace,
|
||||||
name string,
|
name string,
|
||||||
) ([]swarm.NetworkAttachmentConfig, error) {
|
) ([]swarm.NetworkAttachmentConfig, error) {
|
||||||
if len(networks) == 0 {
|
if len(networks) == 0 {
|
||||||
networks = map[string]*composetypes.ServiceNetworkConfig{
|
networks = map[string]*composeGoTypes.ServiceNetworkConfig{
|
||||||
defaultNetwork: {},
|
defaultNetwork: {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -403,20 +420,20 @@ func convertServiceNetworks(
|
|||||||
func convertServiceSecrets(
|
func convertServiceSecrets(
|
||||||
client client.SecretAPIClient,
|
client client.SecretAPIClient,
|
||||||
namespace Namespace,
|
namespace Namespace,
|
||||||
secrets []composetypes.ServiceSecretConfig,
|
secrets []composeGoTypes.ServiceSecretConfig,
|
||||||
secretSpecs map[string]composetypes.SecretConfig,
|
secretSpecs map[string]composeGoTypes.SecretConfig,
|
||||||
) ([]*swarm.SecretReference, error) {
|
) ([]*swarm.SecretReference, error) {
|
||||||
refs := []*swarm.SecretReference{}
|
refs := []*swarm.SecretReference{}
|
||||||
|
|
||||||
lookup := func(key string) (composetypes.FileObjectConfig, error) {
|
lookup := func(key string) (composeGoTypes.FileObjectConfig, error) {
|
||||||
secretSpec, exists := secretSpecs[key]
|
secretSpec, exists := secretSpecs[key]
|
||||||
if !exists {
|
if !exists {
|
||||||
return composetypes.FileObjectConfig{}, errors.New(i18n.G("undefined secret %q", key))
|
return composeGoTypes.FileObjectConfig{}, errors.New(i18n.G("undefined secret %q", key))
|
||||||
}
|
}
|
||||||
return composetypes.FileObjectConfig(secretSpec), nil
|
return composeGoTypes.FileObjectConfig(secretSpec), nil
|
||||||
}
|
}
|
||||||
for _, secret := range secrets {
|
for _, secret := range secrets {
|
||||||
obj, err := convertFileObject(namespace, composetypes.FileReferenceConfig(secret), lookup)
|
obj, err := convertFileObject(namespace, composeGoTypes.FileReferenceConfig(secret), lookup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -451,20 +468,20 @@ func convertServiceSecrets(
|
|||||||
func convertServiceConfigObjs(
|
func convertServiceConfigObjs(
|
||||||
client client.ConfigAPIClient,
|
client client.ConfigAPIClient,
|
||||||
namespace Namespace,
|
namespace Namespace,
|
||||||
service composetypes.ServiceConfig,
|
service composeGoTypes.ServiceConfig,
|
||||||
configSpecs map[string]composetypes.ConfigObjConfig,
|
configSpecs map[string]composeGoTypes.ConfigObjConfig,
|
||||||
) ([]*swarm.ConfigReference, error) {
|
) ([]*swarm.ConfigReference, error) {
|
||||||
refs := []*swarm.ConfigReference{}
|
refs := []*swarm.ConfigReference{}
|
||||||
|
|
||||||
lookup := func(key string) (composetypes.FileObjectConfig, error) {
|
lookup := func(key string) (composeGoTypes.FileObjectConfig, error) {
|
||||||
configSpec, exists := configSpecs[key]
|
configSpec, exists := configSpecs[key]
|
||||||
if !exists {
|
if !exists {
|
||||||
return composetypes.FileObjectConfig{}, errors.New(i18n.G("undefined config %q", key))
|
return composeGoTypes.FileObjectConfig{}, errors.New(i18n.G("undefined config %q", key))
|
||||||
}
|
}
|
||||||
return composetypes.FileObjectConfig(configSpec), nil
|
return composeGoTypes.FileObjectConfig(configSpec), nil
|
||||||
}
|
}
|
||||||
for _, config := range service.Configs {
|
for _, config := range service.Configs {
|
||||||
obj, err := convertFileObject(namespace, composetypes.FileReferenceConfig(config), lookup)
|
obj, err := convertFileObject(namespace, composeGoTypes.FileReferenceConfig(config), lookup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -487,7 +504,7 @@ func convertServiceConfigObjs(
|
|||||||
// if the credSpec uses a config, then we should grab the config name, and
|
// if the credSpec uses a config, then we should grab the config name, and
|
||||||
// create a config reference for it. A File or Registry-type CredentialSpec
|
// create a config reference for it. A File or Registry-type CredentialSpec
|
||||||
// does not need this operation.
|
// does not need this operation.
|
||||||
if credSpec.Config != "" {
|
if credSpec != nil && credSpec.Config != "" {
|
||||||
// look up the config in the configSpecs.
|
// look up the config in the configSpecs.
|
||||||
obj, err := lookup(credSpec.Config)
|
obj, err := lookup(credSpec.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -532,8 +549,8 @@ type swarmReferenceObject struct {
|
|||||||
|
|
||||||
func convertFileObject(
|
func convertFileObject(
|
||||||
namespace Namespace,
|
namespace Namespace,
|
||||||
config composetypes.FileReferenceConfig,
|
config composeGoTypes.FileReferenceConfig,
|
||||||
lookup func(key string) (composetypes.FileObjectConfig, error),
|
lookup func(key string) (composeGoTypes.FileObjectConfig, error),
|
||||||
) (swarmReferenceObject, error) {
|
) (swarmReferenceObject, error) {
|
||||||
obj, err := lookup(config.Source)
|
obj, err := lookup(config.Source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -558,40 +575,37 @@ func convertFileObject(
|
|||||||
if gid == "" {
|
if gid == "" {
|
||||||
gid = "0"
|
gid = "0"
|
||||||
}
|
}
|
||||||
mode := config.Mode
|
|
||||||
if mode == nil {
|
|
||||||
mode = uint32Ptr(0444)
|
|
||||||
}
|
|
||||||
|
|
||||||
return swarmReferenceObject{
|
ref := swarmReferenceObject{
|
||||||
File: swarmReferenceTarget{
|
File: swarmReferenceTarget{
|
||||||
Name: target,
|
Name: target,
|
||||||
UID: uid,
|
UID: uid,
|
||||||
GID: gid,
|
GID: gid,
|
||||||
Mode: os.FileMode(*mode),
|
|
||||||
},
|
},
|
||||||
Name: source,
|
Name: source,
|
||||||
}, nil
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func uint32Ptr(value uint32) *uint32 {
|
if config.Mode == nil {
|
||||||
return &value
|
defaultMode := 0444
|
||||||
|
ref.File.Mode = os.FileMode(defaultMode)
|
||||||
|
} else {
|
||||||
|
ref.File.Mode = os.FileMode(*config.Mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertExtraHosts converts <host>:<ip> mappings to SwarmKit notation:
|
// convertExtraHosts converts <host>:<ip> mappings to SwarmKit notation:
|
||||||
// "IP-address hostname(s)". The original order of mappings is preserved.
|
// "IP-address hostname(s)". The original order of mappings is preserved.
|
||||||
func convertExtraHosts(extraHosts composetypes.HostsList) []string {
|
func convertExtraHosts(extraHosts composeGoTypes.HostsList) []string {
|
||||||
hosts := []string{}
|
hosts := []string{}
|
||||||
for _, hostIP := range extraHosts {
|
for hostName, hostIP := range extraHosts {
|
||||||
if v := strings.SplitN(hostIP, ":", 2); len(v) == 2 {
|
hosts = append(hosts, fmt.Sprintf("%s %s", hostIP, hostName))
|
||||||
// Convert to SwarmKit notation: IP-address hostname(s)
|
|
||||||
hosts = append(hosts, fmt.Sprintf("%s %s", v[1], v[0]))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return hosts
|
return hosts
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container.HealthConfig, error) {
|
func convertHealthcheck(healthcheck *composeGoTypes.HealthCheckConfig) (*container.HealthConfig, error) {
|
||||||
if healthcheck == nil {
|
if healthcheck == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -629,7 +643,7 @@ func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertRestartPolicy(restart string, source *composetypes.RestartPolicy) (*swarm.RestartPolicy, error) {
|
func convertRestartPolicy(restart string, source *composeGoTypes.RestartPolicy) (*swarm.RestartPolicy, error) {
|
||||||
if source == nil {
|
if source == nil {
|
||||||
policy, err := opts.ParseRestartPolicy(restart)
|
policy, err := opts.ParseRestartPolicy(restart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -653,15 +667,25 @@ func convertRestartPolicy(restart string, source *composetypes.RestartPolicy) (*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var windowPtr time.Duration
|
||||||
|
if source.Window != nil {
|
||||||
|
windowPtr = time.Duration(*source.Window)
|
||||||
|
}
|
||||||
|
|
||||||
|
var delayPtr time.Duration
|
||||||
|
if source.Delay != nil {
|
||||||
|
delayPtr = time.Duration(*source.Delay)
|
||||||
|
}
|
||||||
|
|
||||||
return &swarm.RestartPolicy{
|
return &swarm.RestartPolicy{
|
||||||
Condition: swarm.RestartPolicyCondition(source.Condition),
|
Condition: swarm.RestartPolicyCondition(source.Condition),
|
||||||
Delay: composetypes.ConvertDurationPtr(source.Delay),
|
Delay: &delayPtr,
|
||||||
MaxAttempts: source.MaxAttempts,
|
MaxAttempts: source.MaxAttempts,
|
||||||
Window: composetypes.ConvertDurationPtr(source.Window),
|
Window: &windowPtr,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertUpdateConfig(source *composetypes.UpdateConfig) *swarm.UpdateConfig {
|
func convertUpdateConfig(source *composeGoTypes.UpdateConfig) *swarm.UpdateConfig {
|
||||||
if source == nil {
|
if source == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -679,13 +703,13 @@ func convertUpdateConfig(source *composetypes.UpdateConfig) *swarm.UpdateConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertResources(source composetypes.Resources) (*swarm.ResourceRequirements, error) {
|
func convertResources(source composeGoTypes.Resources) (*swarm.ResourceRequirements, error) {
|
||||||
resources := &swarm.ResourceRequirements{}
|
resources := &swarm.ResourceRequirements{}
|
||||||
var err error
|
var err error
|
||||||
if source.Limits != nil {
|
if source.Limits != nil {
|
||||||
var cpus int64
|
var cpus int64
|
||||||
if source.Limits.NanoCPUs != "" {
|
if source.Limits.NanoCPUs > 0 {
|
||||||
cpus, err = opts.ParseCPUs(source.Limits.NanoCPUs)
|
cpus, err = opts.ParseCPUs(fmt.Sprintf("%f", source.Limits.NanoCPUs))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -698,8 +722,8 @@ func convertResources(source composetypes.Resources) (*swarm.ResourceRequirement
|
|||||||
}
|
}
|
||||||
if source.Reservations != nil {
|
if source.Reservations != nil {
|
||||||
var cpus int64
|
var cpus int64
|
||||||
if source.Reservations.NanoCPUs != "" {
|
if source.Reservations.NanoCPUs > 0 {
|
||||||
cpus, err = opts.ParseCPUs(source.Reservations.NanoCPUs)
|
cpus, err = opts.ParseCPUs(fmt.Sprintf("%f", source.Reservations.NanoCPUs))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -728,13 +752,29 @@ func convertResources(source composetypes.Resources) (*swarm.ResourceRequirement
|
|||||||
return resources, nil
|
return resources, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertEndpointSpec(endpointMode string, source []composetypes.ServicePortConfig) *swarm.EndpointSpec {
|
func str2uint32(s string) (uint32, error) {
|
||||||
|
var u32 uint32
|
||||||
|
|
||||||
|
u64, err := strconv.ParseUint(s, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return u32, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint32(u64), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertEndpointSpec(endpointMode string, source []composeGoTypes.ServicePortConfig) (*swarm.EndpointSpec, error) {
|
||||||
portConfigs := []swarm.PortConfig{}
|
portConfigs := []swarm.PortConfig{}
|
||||||
for _, port := range source {
|
for _, port := range source {
|
||||||
|
published, err := str2uint32(port.Published)
|
||||||
|
if err != nil {
|
||||||
|
return &swarm.EndpointSpec{}, err
|
||||||
|
}
|
||||||
|
|
||||||
portConfig := swarm.PortConfig{
|
portConfig := swarm.PortConfig{
|
||||||
Protocol: swarm.PortConfigProtocol(port.Protocol),
|
Protocol: swarm.PortConfigProtocol(port.Protocol),
|
||||||
TargetPort: port.Target,
|
TargetPort: port.Target,
|
||||||
PublishedPort: port.Published,
|
PublishedPort: published,
|
||||||
PublishMode: swarm.PortConfigPublishMode(port.Mode),
|
PublishMode: swarm.PortConfigPublishMode(port.Mode),
|
||||||
}
|
}
|
||||||
portConfigs = append(portConfigs, portConfig)
|
portConfigs = append(portConfigs, portConfig)
|
||||||
@ -747,7 +787,7 @@ func convertEndpointSpec(endpointMode string, source []composetypes.ServicePortC
|
|||||||
return &swarm.EndpointSpec{
|
return &swarm.EndpointSpec{
|
||||||
Mode: swarm.ResolutionMode(strings.ToLower(endpointMode)),
|
Mode: swarm.ResolutionMode(strings.ToLower(endpointMode)),
|
||||||
Ports: portConfigs,
|
Ports: portConfigs,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertEnvironment(source map[string]*string) []string {
|
func convertEnvironment(source map[string]*string) []string {
|
||||||
@ -765,7 +805,7 @@ func convertEnvironment(source map[string]*string) []string {
|
|||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertDeployMode(mode string, replicas *uint64) (swarm.ServiceMode, error) {
|
func convertDeployMode(mode string, replicas *int) (swarm.ServiceMode, error) {
|
||||||
serviceMode := swarm.ServiceMode{}
|
serviceMode := swarm.ServiceMode{}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
@ -775,7 +815,8 @@ func convertDeployMode(mode string, replicas *uint64) (swarm.ServiceMode, error)
|
|||||||
}
|
}
|
||||||
serviceMode.Global = &swarm.GlobalService{}
|
serviceMode.Global = &swarm.GlobalService{}
|
||||||
case "replicated", "":
|
case "replicated", "":
|
||||||
serviceMode.Replicated = &swarm.ReplicatedService{Replicas: replicas}
|
convReplicas := (*uint64)(unsafe.Pointer(replicas))
|
||||||
|
serviceMode.Replicated = &swarm.ReplicatedService{Replicas: convReplicas}
|
||||||
default:
|
default:
|
||||||
return serviceMode, errors.New(i18n.G("unknown mode: %s", mode))
|
return serviceMode, errors.New(i18n.G("unknown mode: %s", mode))
|
||||||
}
|
}
|
||||||
@ -792,7 +833,7 @@ func convertDNSConfig(DNS []string, DNSSearch []string) *swarm.DNSConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertCredentialSpec(namespace Namespace, spec composetypes.CredentialSpecConfig, refs []*swarm.ConfigReference) (*swarm.CredentialSpec, error) {
|
func convertCredentialSpec(namespace Namespace, spec composeGoTypes.CredentialSpecConfig, refs []*swarm.ConfigReference) (*swarm.CredentialSpec, error) {
|
||||||
var o []string
|
var o []string
|
||||||
|
|
||||||
// Config was added in API v1.40
|
// Config was added in API v1.40
|
||||||
@ -814,7 +855,13 @@ func convertCredentialSpec(namespace Namespace, spec composetypes.CredentialSpec
|
|||||||
case l > 2:
|
case l > 2:
|
||||||
return nil, errors.New(i18n.G("invalid credential spec: cannot specify both %s, and %s", strings.Join(o[:l-1], ", "), o[l-1]))
|
return nil, errors.New(i18n.G("invalid credential spec: cannot specify both %s, and %s", strings.Join(o[:l-1], ", "), o[l-1]))
|
||||||
}
|
}
|
||||||
swarmCredSpec := swarm.CredentialSpec(spec)
|
|
||||||
|
swarmCredSpec := swarm.CredentialSpec{
|
||||||
|
Config: spec.Config,
|
||||||
|
File: spec.File,
|
||||||
|
Registry: spec.Registry,
|
||||||
|
}
|
||||||
|
|
||||||
// if we're using a swarm Config for the credential spec, over-write it
|
// if we're using a swarm Config for the credential spec, over-write it
|
||||||
// here with the config ID
|
// here with the config ID
|
||||||
if swarmCredSpec.Config != "" {
|
if swarmCredSpec.Config != "" {
|
||||||
@ -836,7 +883,7 @@ func convertCredentialSpec(namespace Namespace, spec composetypes.CredentialSpec
|
|||||||
return &swarmCredSpec, nil
|
return &swarmCredSpec, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertUlimits(origUlimits map[string]*composetypes.UlimitsConfig) []*units.Ulimit {
|
func convertUlimits(origUlimits map[string]*composeGoTypes.UlimitsConfig) []*units.Ulimit {
|
||||||
newUlimits := make(map[string]*units.Ulimit)
|
newUlimits := make(map[string]*units.Ulimit)
|
||||||
for name, u := range origUlimits {
|
for name, u := range origUlimits {
|
||||||
if u.Single != 0 {
|
if u.Single != 0 {
|
||||||
|
|||||||
@ -1,678 +0,0 @@
|
|||||||
package convert // https://github.com/docker/cli/blob/master/cli/compose/convert/service_test.go
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/container"
|
|
||||||
"github.com/docker/docker/api/types/swarm"
|
|
||||||
"github.com/docker/docker/client"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConvertRestartPolicyFromNone(t *testing.T) {
|
|
||||||
policy, err := convertRestartPolicy("no", nil)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual((*swarm.RestartPolicy)(nil), policy))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertRestartPolicyFromUnknown(t *testing.T) {
|
|
||||||
_, err := convertRestartPolicy("unknown", nil)
|
|
||||||
assert.Error(t, err, "unknown restart policy: unknown")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertRestartPolicyFromAlways(t *testing.T) {
|
|
||||||
policy, err := convertRestartPolicy("always", nil)
|
|
||||||
expected := &swarm.RestartPolicy{
|
|
||||||
Condition: swarm.RestartPolicyConditionAny,
|
|
||||||
}
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, policy))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertRestartPolicyFromFailure(t *testing.T) {
|
|
||||||
policy, err := convertRestartPolicy("on-failure:4", nil)
|
|
||||||
attempts := uint64(4)
|
|
||||||
expected := &swarm.RestartPolicy{
|
|
||||||
Condition: swarm.RestartPolicyConditionOnFailure,
|
|
||||||
MaxAttempts: &attempts,
|
|
||||||
}
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, policy))
|
|
||||||
}
|
|
||||||
|
|
||||||
func strPtr(val string) *string {
|
|
||||||
return &val
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertEnvironment(t *testing.T) {
|
|
||||||
source := map[string]*string{
|
|
||||||
"foo": strPtr("bar"),
|
|
||||||
"key": strPtr("value"),
|
|
||||||
}
|
|
||||||
env := convertEnvironment(source)
|
|
||||||
sort.Strings(env)
|
|
||||||
assert.Check(t, is.DeepEqual([]string{"foo=bar", "key=value"}, env))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertExtraHosts(t *testing.T) {
|
|
||||||
source := composetypes.HostsList{
|
|
||||||
"zulu:127.0.0.2",
|
|
||||||
"alpha:127.0.0.1",
|
|
||||||
"zulu:ff02::1",
|
|
||||||
}
|
|
||||||
assert.Check(t, is.DeepEqual([]string{"127.0.0.2 zulu", "127.0.0.1 alpha", "ff02::1 zulu"}, convertExtraHosts(source)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertResourcesFull(t *testing.T) {
|
|
||||||
source := composetypes.Resources{
|
|
||||||
Limits: &composetypes.ResourceLimit{
|
|
||||||
NanoCPUs: "0.003",
|
|
||||||
MemoryBytes: composetypes.UnitBytes(300000000),
|
|
||||||
},
|
|
||||||
Reservations: &composetypes.Resource{
|
|
||||||
NanoCPUs: "0.002",
|
|
||||||
MemoryBytes: composetypes.UnitBytes(200000000),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
resources, err := convertResources(source)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
expected := &swarm.ResourceRequirements{
|
|
||||||
Limits: &swarm.Limit{
|
|
||||||
NanoCPUs: 3000000,
|
|
||||||
MemoryBytes: 300000000,
|
|
||||||
},
|
|
||||||
Reservations: &swarm.Resources{
|
|
||||||
NanoCPUs: 2000000,
|
|
||||||
MemoryBytes: 200000000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.Check(t, is.DeepEqual(expected, resources))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertResourcesOnlyMemory(t *testing.T) {
|
|
||||||
source := composetypes.Resources{
|
|
||||||
Limits: &composetypes.ResourceLimit{
|
|
||||||
MemoryBytes: composetypes.UnitBytes(300000000),
|
|
||||||
},
|
|
||||||
Reservations: &composetypes.Resource{
|
|
||||||
MemoryBytes: composetypes.UnitBytes(200000000),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
resources, err := convertResources(source)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
expected := &swarm.ResourceRequirements{
|
|
||||||
Limits: &swarm.Limit{
|
|
||||||
MemoryBytes: 300000000,
|
|
||||||
},
|
|
||||||
Reservations: &swarm.Resources{
|
|
||||||
MemoryBytes: 200000000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.Check(t, is.DeepEqual(expected, resources))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertHealthcheck(t *testing.T) {
|
|
||||||
retries := uint64(10)
|
|
||||||
timeout := composetypes.Duration(30 * time.Second)
|
|
||||||
interval := composetypes.Duration(2 * time.Millisecond)
|
|
||||||
source := &composetypes.HealthCheckConfig{
|
|
||||||
Test: []string{"EXEC", "touch", "/foo"},
|
|
||||||
Timeout: &timeout,
|
|
||||||
Interval: &interval,
|
|
||||||
Retries: &retries,
|
|
||||||
}
|
|
||||||
expected := &container.HealthConfig{
|
|
||||||
Test: source.Test,
|
|
||||||
Timeout: time.Duration(timeout),
|
|
||||||
Interval: time.Duration(interval),
|
|
||||||
Retries: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
healthcheck, err := convertHealthcheck(source)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, healthcheck))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertHealthcheckDisable(t *testing.T) {
|
|
||||||
source := &composetypes.HealthCheckConfig{Disable: true}
|
|
||||||
expected := &container.HealthConfig{
|
|
||||||
Test: []string{"NONE"},
|
|
||||||
}
|
|
||||||
|
|
||||||
healthcheck, err := convertHealthcheck(source)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, healthcheck))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertHealthcheckDisableWithTest(t *testing.T) {
|
|
||||||
source := &composetypes.HealthCheckConfig{
|
|
||||||
Disable: true,
|
|
||||||
Test: []string{"EXEC", "touch"},
|
|
||||||
}
|
|
||||||
_, err := convertHealthcheck(source)
|
|
||||||
assert.Error(t, err, "test and disable can't be set at the same time")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertEndpointSpec(t *testing.T) {
|
|
||||||
source := []composetypes.ServicePortConfig{
|
|
||||||
{
|
|
||||||
Protocol: "udp",
|
|
||||||
Target: 53,
|
|
||||||
Published: 1053,
|
|
||||||
Mode: "host",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Target: 8080,
|
|
||||||
Published: 80,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
endpoint := convertEndpointSpec("vip", source)
|
|
||||||
|
|
||||||
expected := swarm.EndpointSpec{
|
|
||||||
Mode: swarm.ResolutionMode(strings.ToLower("vip")),
|
|
||||||
Ports: []swarm.PortConfig{
|
|
||||||
{
|
|
||||||
TargetPort: 8080,
|
|
||||||
PublishedPort: 80,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Protocol: "udp",
|
|
||||||
TargetPort: 53,
|
|
||||||
PublishedPort: 1053,
|
|
||||||
PublishMode: "host",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Check(t, is.DeepEqual(expected, *endpoint))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertServiceNetworksOnlyDefault(t *testing.T) {
|
|
||||||
networkConfigs := networkMap{}
|
|
||||||
|
|
||||||
configs, err := convertServiceNetworks(
|
|
||||||
nil, networkConfigs, NewNamespace("foo"), "service")
|
|
||||||
|
|
||||||
expected := []swarm.NetworkAttachmentConfig{
|
|
||||||
{
|
|
||||||
Target: "foo_default",
|
|
||||||
Aliases: []string{"service"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, configs))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertServiceNetworks(t *testing.T) {
|
|
||||||
networkConfigs := networkMap{
|
|
||||||
"front": composetypes.NetworkConfig{
|
|
||||||
External: composetypes.External{External: true},
|
|
||||||
Name: "fronttier",
|
|
||||||
},
|
|
||||||
"back": composetypes.NetworkConfig{},
|
|
||||||
}
|
|
||||||
networks := map[string]*composetypes.ServiceNetworkConfig{
|
|
||||||
"front": {
|
|
||||||
Aliases: []string{"something"},
|
|
||||||
},
|
|
||||||
"back": {
|
|
||||||
Aliases: []string{"other"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
configs, err := convertServiceNetworks(
|
|
||||||
networks, networkConfigs, NewNamespace("foo"), "service")
|
|
||||||
|
|
||||||
expected := []swarm.NetworkAttachmentConfig{
|
|
||||||
{
|
|
||||||
Target: "foo_back",
|
|
||||||
Aliases: []string{"other", "service"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Target: "fronttier",
|
|
||||||
Aliases: []string{"something", "service"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, configs))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertServiceNetworksCustomDefault(t *testing.T) {
|
|
||||||
networkConfigs := networkMap{
|
|
||||||
"default": composetypes.NetworkConfig{
|
|
||||||
External: composetypes.External{External: true},
|
|
||||||
Name: "custom",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
networks := map[string]*composetypes.ServiceNetworkConfig{}
|
|
||||||
|
|
||||||
configs, err := convertServiceNetworks(
|
|
||||||
networks, networkConfigs, NewNamespace("foo"), "service")
|
|
||||||
|
|
||||||
expected := []swarm.NetworkAttachmentConfig{
|
|
||||||
{
|
|
||||||
Target: "custom",
|
|
||||||
Aliases: []string{"service"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, configs))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertDNSConfigEmpty(t *testing.T) {
|
|
||||||
dnsConfig := convertDNSConfig(nil, nil)
|
|
||||||
assert.Check(t, is.DeepEqual((*swarm.DNSConfig)(nil), dnsConfig))
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
nameservers = []string{"8.8.8.8", "9.9.9.9"}
|
|
||||||
search = []string{"dc1.example.com", "dc2.example.com"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConvertDNSConfigAll(t *testing.T) {
|
|
||||||
dnsConfig := convertDNSConfig(nameservers, search)
|
|
||||||
assert.Check(t, is.DeepEqual(&swarm.DNSConfig{
|
|
||||||
Nameservers: nameservers,
|
|
||||||
Search: search,
|
|
||||||
}, dnsConfig))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertDNSConfigNameservers(t *testing.T) {
|
|
||||||
dnsConfig := convertDNSConfig(nameservers, nil)
|
|
||||||
assert.Check(t, is.DeepEqual(&swarm.DNSConfig{
|
|
||||||
Nameservers: nameservers,
|
|
||||||
Search: nil,
|
|
||||||
}, dnsConfig))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertDNSConfigSearch(t *testing.T) {
|
|
||||||
dnsConfig := convertDNSConfig(nil, search)
|
|
||||||
assert.Check(t, is.DeepEqual(&swarm.DNSConfig{
|
|
||||||
Nameservers: nil,
|
|
||||||
Search: search,
|
|
||||||
}, dnsConfig))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertCredentialSpec(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
in composetypes.CredentialSpecConfig
|
|
||||||
out *swarm.CredentialSpec
|
|
||||||
configs []*swarm.ConfigReference
|
|
||||||
expectedErr string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "empty",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "config-and-file",
|
|
||||||
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq", File: "somefile.json"},
|
|
||||||
expectedErr: `invalid credential spec: cannot specify both "Config" and "File"`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "config-and-registry",
|
|
||||||
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq", Registry: "testing"},
|
|
||||||
expectedErr: `invalid credential spec: cannot specify both "Config" and "Registry"`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "file-and-registry",
|
|
||||||
in: composetypes.CredentialSpecConfig{File: "somefile.json", Registry: "testing"},
|
|
||||||
expectedErr: `invalid credential spec: cannot specify both "File" and "Registry"`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "config-and-file-and-registry",
|
|
||||||
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq", File: "somefile.json", Registry: "testing"},
|
|
||||||
expectedErr: `invalid credential spec: cannot specify both "Config", "File", and "Registry"`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "missing-config-reference",
|
|
||||||
in: composetypes.CredentialSpecConfig{Config: "missing"},
|
|
||||||
expectedErr: "invalid credential spec: spec specifies config missing, but no such config can be found",
|
|
||||||
configs: []*swarm.ConfigReference{
|
|
||||||
{
|
|
||||||
ConfigName: "someName",
|
|
||||||
ConfigID: "missing",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "namespaced-config",
|
|
||||||
in: composetypes.CredentialSpecConfig{Config: "name"},
|
|
||||||
configs: []*swarm.ConfigReference{
|
|
||||||
{
|
|
||||||
ConfigName: "namespaced-config_name",
|
|
||||||
ConfigID: "someID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
out: &swarm.CredentialSpec{Config: "someID"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "config",
|
|
||||||
in: composetypes.CredentialSpecConfig{Config: "someName"},
|
|
||||||
configs: []*swarm.ConfigReference{
|
|
||||||
{
|
|
||||||
ConfigName: "someOtherName",
|
|
||||||
ConfigID: "someOtherID",
|
|
||||||
}, {
|
|
||||||
ConfigName: "someName",
|
|
||||||
ConfigID: "someID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
out: &swarm.CredentialSpec{Config: "someID"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "file",
|
|
||||||
in: composetypes.CredentialSpecConfig{File: "somefile.json"},
|
|
||||||
out: &swarm.CredentialSpec{File: "somefile.json"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "registry",
|
|
||||||
in: composetypes.CredentialSpecConfig{Registry: "testing"},
|
|
||||||
out: &swarm.CredentialSpec{Registry: "testing"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
tc := tc
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
namespace := NewNamespace(tc.name)
|
|
||||||
swarmSpec, err := convertCredentialSpec(namespace, tc.in, tc.configs)
|
|
||||||
|
|
||||||
if tc.expectedErr != "" {
|
|
||||||
assert.Error(t, err, tc.expectedErr)
|
|
||||||
} else {
|
|
||||||
assert.NilError(t, err)
|
|
||||||
}
|
|
||||||
assert.DeepEqual(t, swarmSpec, tc.out)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertUpdateConfigOrder(t *testing.T) {
|
|
||||||
// test default behavior
|
|
||||||
updateConfig := convertUpdateConfig(&composetypes.UpdateConfig{})
|
|
||||||
assert.Check(t, is.Equal("", updateConfig.Order))
|
|
||||||
|
|
||||||
// test start-first
|
|
||||||
updateConfig = convertUpdateConfig(&composetypes.UpdateConfig{
|
|
||||||
Order: "start-first",
|
|
||||||
})
|
|
||||||
assert.Check(t, is.Equal(updateConfig.Order, "start-first"))
|
|
||||||
|
|
||||||
// test stop-first
|
|
||||||
updateConfig = convertUpdateConfig(&composetypes.UpdateConfig{
|
|
||||||
Order: "stop-first",
|
|
||||||
})
|
|
||||||
assert.Check(t, is.Equal(updateConfig.Order, "stop-first"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertFileObject(t *testing.T) {
|
|
||||||
namespace := NewNamespace("testing")
|
|
||||||
config := composetypes.FileReferenceConfig{
|
|
||||||
Source: "source",
|
|
||||||
Target: "target",
|
|
||||||
UID: "user",
|
|
||||||
GID: "group",
|
|
||||||
Mode: uint32Ptr(0644),
|
|
||||||
}
|
|
||||||
swarmRef, err := convertFileObject(namespace, config, lookupConfig)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
expected := swarmReferenceObject{
|
|
||||||
Name: "testing_source",
|
|
||||||
File: swarmReferenceTarget{
|
|
||||||
Name: config.Target,
|
|
||||||
UID: config.UID,
|
|
||||||
GID: config.GID,
|
|
||||||
Mode: os.FileMode(0644),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.Check(t, is.DeepEqual(expected, swarmRef))
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupConfig(key string) (composetypes.FileObjectConfig, error) {
|
|
||||||
if key != "source" {
|
|
||||||
return composetypes.FileObjectConfig{}, errors.New("bad key")
|
|
||||||
}
|
|
||||||
return composetypes.FileObjectConfig{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertFileObjectDefaults(t *testing.T) {
|
|
||||||
namespace := NewNamespace("testing")
|
|
||||||
config := composetypes.FileReferenceConfig{Source: "source"}
|
|
||||||
swarmRef, err := convertFileObject(namespace, config, lookupConfig)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
expected := swarmReferenceObject{
|
|
||||||
Name: "testing_source",
|
|
||||||
File: swarmReferenceTarget{
|
|
||||||
Name: config.Source,
|
|
||||||
UID: "0",
|
|
||||||
GID: "0",
|
|
||||||
Mode: os.FileMode(0444),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.Check(t, is.DeepEqual(expected, swarmRef))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceConvertsIsolation(t *testing.T) {
|
|
||||||
src := composetypes.ServiceConfig{
|
|
||||||
Isolation: "hyperv",
|
|
||||||
}
|
|
||||||
result, err := Service("1.35", Namespace{name: "foo"}, src, nil, nil, nil, nil)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.Equal(container.IsolationHyperV, result.TaskTemplate.ContainerSpec.Isolation))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertServiceSecrets(t *testing.T) {
|
|
||||||
namespace := Namespace{name: "foo"}
|
|
||||||
secrets := []composetypes.ServiceSecretConfig{
|
|
||||||
{Source: "foo_secret"},
|
|
||||||
{Source: "bar_secret"},
|
|
||||||
}
|
|
||||||
secretSpecs := map[string]composetypes.SecretConfig{
|
|
||||||
"foo_secret": {
|
|
||||||
Name: "foo_secret",
|
|
||||||
},
|
|
||||||
"bar_secret": {
|
|
||||||
Name: "bar_secret",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
client := &fakeClient{
|
|
||||||
secretListFunc: func(opts types.SecretListOptions) ([]swarm.Secret, error) {
|
|
||||||
assert.Check(t, is.Contains(opts.Filters.Get("name"), "foo_secret"))
|
|
||||||
assert.Check(t, is.Contains(opts.Filters.Get("name"), "bar_secret"))
|
|
||||||
return []swarm.Secret{
|
|
||||||
{Spec: swarm.SecretSpec{Annotations: swarm.Annotations{Name: "foo_secret"}}},
|
|
||||||
{Spec: swarm.SecretSpec{Annotations: swarm.Annotations{Name: "bar_secret"}}},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
refs, err := convertServiceSecrets(client, namespace, secrets, secretSpecs)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
expected := []*swarm.SecretReference{
|
|
||||||
{
|
|
||||||
SecretName: "bar_secret",
|
|
||||||
File: &swarm.SecretReferenceFileTarget{
|
|
||||||
Name: "bar_secret",
|
|
||||||
UID: "0",
|
|
||||||
GID: "0",
|
|
||||||
Mode: 0444,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
SecretName: "foo_secret",
|
|
||||||
File: &swarm.SecretReferenceFileTarget{
|
|
||||||
Name: "foo_secret",
|
|
||||||
UID: "0",
|
|
||||||
GID: "0",
|
|
||||||
Mode: 0444,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.DeepEqual(t, expected, refs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertServiceConfigs(t *testing.T) {
|
|
||||||
namespace := Namespace{name: "foo"}
|
|
||||||
service := composetypes.ServiceConfig{
|
|
||||||
Configs: []composetypes.ServiceConfigObjConfig{
|
|
||||||
{Source: "foo_config"},
|
|
||||||
{Source: "bar_config"},
|
|
||||||
},
|
|
||||||
CredentialSpec: composetypes.CredentialSpecConfig{
|
|
||||||
Config: "baz_config",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
configSpecs := map[string]composetypes.ConfigObjConfig{
|
|
||||||
"foo_config": {
|
|
||||||
Name: "foo_config",
|
|
||||||
},
|
|
||||||
"bar_config": {
|
|
||||||
Name: "bar_config",
|
|
||||||
},
|
|
||||||
"baz_config": {
|
|
||||||
Name: "baz_config",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
client := &fakeClient{
|
|
||||||
configListFunc: func(opts types.ConfigListOptions) ([]swarm.Config, error) {
|
|
||||||
assert.Check(t, is.Contains(opts.Filters.Get("name"), "foo_config"))
|
|
||||||
assert.Check(t, is.Contains(opts.Filters.Get("name"), "bar_config"))
|
|
||||||
assert.Check(t, is.Contains(opts.Filters.Get("name"), "baz_config"))
|
|
||||||
return []swarm.Config{
|
|
||||||
{Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "foo_config"}}},
|
|
||||||
{Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "bar_config"}}},
|
|
||||||
{Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "baz_config"}}},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
refs, err := convertServiceConfigObjs(client, namespace, service, configSpecs)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
expected := []*swarm.ConfigReference{
|
|
||||||
{
|
|
||||||
ConfigName: "bar_config",
|
|
||||||
File: &swarm.ConfigReferenceFileTarget{
|
|
||||||
Name: "bar_config",
|
|
||||||
UID: "0",
|
|
||||||
GID: "0",
|
|
||||||
Mode: 0444,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ConfigName: "baz_config",
|
|
||||||
Runtime: &swarm.ConfigReferenceRuntimeTarget{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ConfigName: "foo_config",
|
|
||||||
File: &swarm.ConfigReferenceFileTarget{
|
|
||||||
Name: "foo_config",
|
|
||||||
UID: "0",
|
|
||||||
GID: "0",
|
|
||||||
Mode: 0444,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.DeepEqual(t, expected, refs)
|
|
||||||
}
|
|
||||||
|
|
||||||
type fakeClient struct {
|
|
||||||
client.Client
|
|
||||||
secretListFunc func(types.SecretListOptions) ([]swarm.Secret, error)
|
|
||||||
configListFunc func(types.ConfigListOptions) ([]swarm.Config, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *fakeClient) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
|
||||||
if c.secretListFunc != nil {
|
|
||||||
return c.secretListFunc(options)
|
|
||||||
}
|
|
||||||
return []swarm.Secret{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *fakeClient) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
|
||||||
if c.configListFunc != nil {
|
|
||||||
return c.configListFunc(options)
|
|
||||||
}
|
|
||||||
return []swarm.Config{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertUpdateConfigParallelism(t *testing.T) {
|
|
||||||
parallel := uint64(4)
|
|
||||||
|
|
||||||
// test default behavior
|
|
||||||
updateConfig := convertUpdateConfig(&composetypes.UpdateConfig{})
|
|
||||||
assert.Check(t, is.Equal(uint64(1), updateConfig.Parallelism))
|
|
||||||
|
|
||||||
// Non default value
|
|
||||||
updateConfig = convertUpdateConfig(&composetypes.UpdateConfig{
|
|
||||||
Parallelism: ¶llel,
|
|
||||||
})
|
|
||||||
assert.Check(t, is.Equal(parallel, updateConfig.Parallelism))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertServiceCapAddAndCapDrop(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
title string
|
|
||||||
in, out composetypes.ServiceConfig
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
title: "default behavior",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "some values",
|
|
||||||
in: composetypes.ServiceConfig{
|
|
||||||
CapAdd: []string{"SYS_NICE", "CAP_NET_ADMIN"},
|
|
||||||
CapDrop: []string{"CHOWN", "CAP_NET_ADMIN", "DAC_OVERRIDE", "CAP_FSETID", "CAP_FOWNER"},
|
|
||||||
},
|
|
||||||
out: composetypes.ServiceConfig{
|
|
||||||
CapAdd: []string{"CAP_NET_ADMIN", "CAP_SYS_NICE"},
|
|
||||||
CapDrop: []string{"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_FSETID"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "adding ALL capabilities",
|
|
||||||
in: composetypes.ServiceConfig{
|
|
||||||
CapAdd: []string{"ALL", "CAP_NET_ADMIN"},
|
|
||||||
CapDrop: []string{"CHOWN", "CAP_NET_ADMIN", "DAC_OVERRIDE", "CAP_FSETID", "CAP_FOWNER"},
|
|
||||||
},
|
|
||||||
out: composetypes.ServiceConfig{
|
|
||||||
CapAdd: []string{"ALL"},
|
|
||||||
CapDrop: []string{"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_FSETID", "CAP_NET_ADMIN"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "dropping ALL capabilities",
|
|
||||||
in: composetypes.ServiceConfig{
|
|
||||||
CapAdd: []string{"CHOWN", "CAP_NET_ADMIN", "DAC_OVERRIDE", "CAP_FSETID", "CAP_FOWNER"},
|
|
||||||
CapDrop: []string{"ALL", "CAP_NET_ADMIN", "CAP_FOO"},
|
|
||||||
},
|
|
||||||
out: composetypes.ServiceConfig{
|
|
||||||
CapAdd: []string{"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_FSETID", "CAP_NET_ADMIN"},
|
|
||||||
CapDrop: []string{"ALL"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range tests {
|
|
||||||
tc := tc
|
|
||||||
t.Run(tc.title, func(t *testing.T) {
|
|
||||||
result, err := Service("1.41", Namespace{name: "foo"}, tc.in, nil, nil, nil, nil)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(result.TaskTemplate.ContainerSpec.CapabilityAdd, tc.out.CapAdd))
|
|
||||||
assert.Check(t, is.DeepEqual(result.TaskTemplate.ContainerSpec.CapabilityDrop, tc.out.CapDrop))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,15 +2,15 @@ package convert // https://github.com/docker/cli/blob/master/cli/compose/convert
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"coopcloud.tech/abra/pkg/i18n"
|
"coopcloud.tech/abra/pkg/i18n"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
"github.com/docker/docker/api/types/mount"
|
"github.com/docker/docker/api/types/mount"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type volumes map[string]composetypes.VolumeConfig
|
type volumes map[string]composeGoTypes.VolumeConfig
|
||||||
|
|
||||||
// Volumes from compose-file types to engine api types
|
// Volumes from compose-file types to engine api types
|
||||||
func Volumes(serviceVolumes []composetypes.ServiceVolumeConfig, stackVolumes volumes, namespace Namespace) ([]mount.Mount, error) {
|
func Volumes(serviceVolumes []composeGoTypes.ServiceVolumeConfig, stackVolumes volumes, namespace Namespace) ([]mount.Mount, error) {
|
||||||
var mounts []mount.Mount
|
var mounts []mount.Mount
|
||||||
|
|
||||||
for _, volumeConfig := range serviceVolumes {
|
for _, volumeConfig := range serviceVolumes {
|
||||||
@ -23,7 +23,7 @@ func Volumes(serviceVolumes []composetypes.ServiceVolumeConfig, stackVolumes vol
|
|||||||
return mounts, nil
|
return mounts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMountFromVolume(volume composetypes.ServiceVolumeConfig) mount.Mount {
|
func createMountFromVolume(volume composeGoTypes.ServiceVolumeConfig) mount.Mount {
|
||||||
return mount.Mount{
|
return mount.Mount{
|
||||||
Type: mount.Type(volume.Type),
|
Type: mount.Type(volume.Type),
|
||||||
Target: volume.Target,
|
Target: volume.Target,
|
||||||
@ -34,7 +34,7 @@ func createMountFromVolume(volume composetypes.ServiceVolumeConfig) mount.Mount
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleVolumeToMount(
|
func handleVolumeToMount(
|
||||||
volume composetypes.ServiceVolumeConfig,
|
volume composeGoTypes.ServiceVolumeConfig,
|
||||||
stackVolumes volumes,
|
stackVolumes volumes,
|
||||||
namespace Namespace,
|
namespace Namespace,
|
||||||
) (mount.Mount, error) {
|
) (mount.Mount, error) {
|
||||||
@ -68,7 +68,7 @@ func handleVolumeToMount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// External named volumes
|
// External named volumes
|
||||||
if stackVolume.External.External {
|
if stackVolume.External {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ func handleVolumeToMount(
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleBindToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) {
|
func handleBindToMount(volume composeGoTypes.ServiceVolumeConfig) (mount.Mount, error) {
|
||||||
result := createMountFromVolume(volume)
|
result := createMountFromVolume(volume)
|
||||||
|
|
||||||
if volume.Source == "" {
|
if volume.Source == "" {
|
||||||
@ -103,7 +103,7 @@ func handleBindToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, er
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleTmpfsToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) {
|
func handleTmpfsToMount(volume composeGoTypes.ServiceVolumeConfig) (mount.Mount, error) {
|
||||||
result := createMountFromVolume(volume)
|
result := createMountFromVolume(volume)
|
||||||
|
|
||||||
if volume.Source != "" {
|
if volume.Source != "" {
|
||||||
@ -117,13 +117,13 @@ func handleTmpfsToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, e
|
|||||||
}
|
}
|
||||||
if volume.Tmpfs != nil {
|
if volume.Tmpfs != nil {
|
||||||
result.TmpfsOptions = &mount.TmpfsOptions{
|
result.TmpfsOptions = &mount.TmpfsOptions{
|
||||||
SizeBytes: volume.Tmpfs.Size,
|
SizeBytes: int64(volume.Tmpfs.Size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleNpipeToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) {
|
func handleNpipeToMount(volume composeGoTypes.ServiceVolumeConfig) (mount.Mount, error) {
|
||||||
result := createMountFromVolume(volume)
|
result := createMountFromVolume(volume)
|
||||||
|
|
||||||
if volume.Source == "" {
|
if volume.Source == "" {
|
||||||
@ -144,7 +144,7 @@ func handleNpipeToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func convertVolumeToMount(
|
func convertVolumeToMount(
|
||||||
volume composetypes.ServiceVolumeConfig,
|
volume composeGoTypes.ServiceVolumeConfig,
|
||||||
stackVolumes volumes,
|
stackVolumes volumes,
|
||||||
namespace Namespace,
|
namespace Namespace,
|
||||||
) (mount.Mount, error) {
|
) (mount.Mount, error) {
|
||||||
|
|||||||
@ -1,361 +0,0 @@
|
|||||||
package convert // https://github.com/docker/cli/blob/master/cli/compose/convert/volume_test.go
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
|
||||||
"github.com/docker/docker/api/types/mount"
|
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountAnonymousVolume(t *testing.T) {
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "volume",
|
|
||||||
Target: "/foo/bar",
|
|
||||||
}
|
|
||||||
expected := mount.Mount{
|
|
||||||
Type: mount.TypeVolume,
|
|
||||||
Target: "/foo/bar",
|
|
||||||
}
|
|
||||||
mount, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, mount))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountAnonymousBind(t *testing.T) {
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "bind",
|
|
||||||
Target: "/foo/bar",
|
|
||||||
Bind: &composetypes.ServiceVolumeBind{
|
|
||||||
Propagation: "slave",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
|
||||||
assert.Error(t, err, "invalid bind source, source cannot be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountUnapprovedType(t *testing.T) {
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "foo",
|
|
||||||
Target: "/foo/bar",
|
|
||||||
}
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
|
||||||
assert.Error(t, err, "volume type must be volume, bind, tmpfs or npipe")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountConflictingOptionsBindInVolume(t *testing.T) {
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "volume",
|
|
||||||
Source: "foo",
|
|
||||||
Target: "/target",
|
|
||||||
Bind: &composetypes.ServiceVolumeBind{
|
|
||||||
Propagation: "slave",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
|
||||||
assert.Error(t, err, "bind options are incompatible with type volume")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountConflictingOptionsTmpfsInVolume(t *testing.T) {
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "volume",
|
|
||||||
Source: "foo",
|
|
||||||
Target: "/target",
|
|
||||||
Tmpfs: &composetypes.ServiceVolumeTmpfs{
|
|
||||||
Size: 1000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
|
||||||
assert.Error(t, err, "tmpfs options are incompatible with type volume")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountConflictingOptionsVolumeInBind(t *testing.T) {
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "bind",
|
|
||||||
Source: "/foo",
|
|
||||||
Target: "/target",
|
|
||||||
Volume: &composetypes.ServiceVolumeVolume{
|
|
||||||
NoCopy: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
|
||||||
assert.Error(t, err, "volume options are incompatible with type bind")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountConflictingOptionsTmpfsInBind(t *testing.T) {
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "bind",
|
|
||||||
Source: "/foo",
|
|
||||||
Target: "/target",
|
|
||||||
Tmpfs: &composetypes.ServiceVolumeTmpfs{
|
|
||||||
Size: 1000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
|
||||||
assert.Error(t, err, "tmpfs options are incompatible with type bind")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountConflictingOptionsBindInTmpfs(t *testing.T) {
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "tmpfs",
|
|
||||||
Target: "/target",
|
|
||||||
Bind: &composetypes.ServiceVolumeBind{
|
|
||||||
Propagation: "slave",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
|
||||||
assert.Error(t, err, "bind options are incompatible with type tmpfs")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountConflictingOptionsVolumeInTmpfs(t *testing.T) {
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "tmpfs",
|
|
||||||
Target: "/target",
|
|
||||||
Volume: &composetypes.ServiceVolumeVolume{
|
|
||||||
NoCopy: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
|
||||||
assert.Error(t, err, "volume options are incompatible with type tmpfs")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountNamedVolume(t *testing.T) {
|
|
||||||
stackVolumes := volumes{
|
|
||||||
"normal": composetypes.VolumeConfig{
|
|
||||||
Driver: "glusterfs",
|
|
||||||
DriverOpts: map[string]string{
|
|
||||||
"opt": "value",
|
|
||||||
},
|
|
||||||
Labels: map[string]string{
|
|
||||||
"something": "labeled",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
expected := mount.Mount{
|
|
||||||
Type: mount.TypeVolume,
|
|
||||||
Source: "foo_normal",
|
|
||||||
Target: "/foo",
|
|
||||||
ReadOnly: true,
|
|
||||||
VolumeOptions: &mount.VolumeOptions{
|
|
||||||
Labels: map[string]string{
|
|
||||||
LabelNamespace: "foo",
|
|
||||||
"something": "labeled",
|
|
||||||
},
|
|
||||||
DriverConfig: &mount.Driver{
|
|
||||||
Name: "glusterfs",
|
|
||||||
Options: map[string]string{
|
|
||||||
"opt": "value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
NoCopy: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "volume",
|
|
||||||
Source: "normal",
|
|
||||||
Target: "/foo",
|
|
||||||
ReadOnly: true,
|
|
||||||
Volume: &composetypes.ServiceVolumeVolume{
|
|
||||||
NoCopy: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, mount))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountNamedVolumeWithNameCustomizd(t *testing.T) {
|
|
||||||
stackVolumes := volumes{
|
|
||||||
"normal": composetypes.VolumeConfig{
|
|
||||||
Name: "user_specified_name",
|
|
||||||
Driver: "vsphere",
|
|
||||||
DriverOpts: map[string]string{
|
|
||||||
"opt": "value",
|
|
||||||
},
|
|
||||||
Labels: map[string]string{
|
|
||||||
"something": "labeled",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
expected := mount.Mount{
|
|
||||||
Type: mount.TypeVolume,
|
|
||||||
Source: "user_specified_name",
|
|
||||||
Target: "/foo",
|
|
||||||
ReadOnly: true,
|
|
||||||
VolumeOptions: &mount.VolumeOptions{
|
|
||||||
Labels: map[string]string{
|
|
||||||
LabelNamespace: "foo",
|
|
||||||
"something": "labeled",
|
|
||||||
},
|
|
||||||
DriverConfig: &mount.Driver{
|
|
||||||
Name: "vsphere",
|
|
||||||
Options: map[string]string{
|
|
||||||
"opt": "value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
NoCopy: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "volume",
|
|
||||||
Source: "normal",
|
|
||||||
Target: "/foo",
|
|
||||||
ReadOnly: true,
|
|
||||||
Volume: &composetypes.ServiceVolumeVolume{
|
|
||||||
NoCopy: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, mount))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountNamedVolumeExternal(t *testing.T) {
|
|
||||||
stackVolumes := volumes{
|
|
||||||
"outside": composetypes.VolumeConfig{
|
|
||||||
Name: "special",
|
|
||||||
External: composetypes.External{External: true},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
expected := mount.Mount{
|
|
||||||
Type: mount.TypeVolume,
|
|
||||||
Source: "special",
|
|
||||||
Target: "/foo",
|
|
||||||
VolumeOptions: &mount.VolumeOptions{NoCopy: false},
|
|
||||||
}
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "volume",
|
|
||||||
Source: "outside",
|
|
||||||
Target: "/foo",
|
|
||||||
}
|
|
||||||
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, mount))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountNamedVolumeExternalNoCopy(t *testing.T) {
|
|
||||||
stackVolumes := volumes{
|
|
||||||
"outside": composetypes.VolumeConfig{
|
|
||||||
Name: "special",
|
|
||||||
External: composetypes.External{External: true},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
expected := mount.Mount{
|
|
||||||
Type: mount.TypeVolume,
|
|
||||||
Source: "special",
|
|
||||||
Target: "/foo",
|
|
||||||
VolumeOptions: &mount.VolumeOptions{
|
|
||||||
NoCopy: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "volume",
|
|
||||||
Source: "outside",
|
|
||||||
Target: "/foo",
|
|
||||||
Volume: &composetypes.ServiceVolumeVolume{
|
|
||||||
NoCopy: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, mount))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountBind(t *testing.T) {
|
|
||||||
stackVolumes := volumes{}
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
expected := mount.Mount{
|
|
||||||
Type: mount.TypeBind,
|
|
||||||
Source: "/bar",
|
|
||||||
Target: "/foo",
|
|
||||||
ReadOnly: true,
|
|
||||||
BindOptions: &mount.BindOptions{Propagation: mount.PropagationShared},
|
|
||||||
}
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "bind",
|
|
||||||
Source: "/bar",
|
|
||||||
Target: "/foo",
|
|
||||||
ReadOnly: true,
|
|
||||||
Bind: &composetypes.ServiceVolumeBind{Propagation: "shared"},
|
|
||||||
}
|
|
||||||
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, mount))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountVolumeDoesNotExist(t *testing.T) {
|
|
||||||
namespace := NewNamespace("foo")
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "volume",
|
|
||||||
Source: "unknown",
|
|
||||||
Target: "/foo",
|
|
||||||
ReadOnly: true,
|
|
||||||
}
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
|
||||||
assert.Error(t, err, "undefined volume \"unknown\"")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertTmpfsToMountVolume(t *testing.T) {
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "tmpfs",
|
|
||||||
Target: "/foo/bar",
|
|
||||||
Tmpfs: &composetypes.ServiceVolumeTmpfs{
|
|
||||||
Size: 1000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
expected := mount.Mount{
|
|
||||||
Type: mount.TypeTmpfs,
|
|
||||||
Target: "/foo/bar",
|
|
||||||
TmpfsOptions: &mount.TmpfsOptions{SizeBytes: 1000},
|
|
||||||
}
|
|
||||||
mount, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, mount))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertTmpfsToMountVolumeWithSource(t *testing.T) {
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "tmpfs",
|
|
||||||
Source: "/bar",
|
|
||||||
Target: "/foo/bar",
|
|
||||||
Tmpfs: &composetypes.ServiceVolumeTmpfs{
|
|
||||||
Size: 1000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
|
||||||
assert.Error(t, err, "invalid tmpfs source, source must be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertVolumeToMountAnonymousNpipe(t *testing.T) {
|
|
||||||
config := composetypes.ServiceVolumeConfig{
|
|
||||||
Type: "npipe",
|
|
||||||
Source: `\\.\pipe\foo`,
|
|
||||||
Target: `\\.\pipe\foo`,
|
|
||||||
}
|
|
||||||
expected := mount.Mount{
|
|
||||||
Type: mount.TypeNamedPipe,
|
|
||||||
Source: `\\.\pipe\foo`,
|
|
||||||
Target: `\\.\pipe\foo`,
|
|
||||||
}
|
|
||||||
mount, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.DeepEqual(expected, mount))
|
|
||||||
}
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package stack // https://github.com/docker/cli/blob/master/cli/command/stack/loader/loader.go
|
package stack // https://github.com/docker/cli/blob/master/cli/command/stack/loader/loader.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -8,58 +9,62 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"coopcloud.tech/abra/pkg/i18n"
|
"coopcloud.tech/abra/pkg/i18n"
|
||||||
"coopcloud.tech/abra/pkg/log"
|
composeGoCli "github.com/compose-spec/compose-go/v2/cli"
|
||||||
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
"github.com/docker/cli/cli/compose/loader"
|
"github.com/docker/cli/cli/compose/loader"
|
||||||
"github.com/docker/cli/cli/compose/schema"
|
"github.com/docker/cli/cli/compose/schema"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
composetypes "github.com/docker/cli/cli/compose/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DontSkipValidation ensures validation is done for compose file loading
|
type LoadConf struct {
|
||||||
func DontSkipValidation(opts *loader.Options) {
|
ComposeFiles []string
|
||||||
opts.SkipValidation = false
|
AppEnv map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SkipInterpolation skip interpolating environment variables.
|
func LoadCompose(conf LoadConf) (*composeGoTypes.Project, error) {
|
||||||
func SkipInterpolation(opts *loader.Options) {
|
var project *composeGoTypes.Project
|
||||||
opts.SkipInterpolation = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadComposefile parse the composefile specified in the cli and returns its Config and version.
|
// NOTE(d1): silence compose-go internal logger
|
||||||
func LoadComposefile(opts Deploy, appEnv map[string]string, options ...func(*loader.Options)) (*composetypes.Config, error) {
|
logrus.SetOutput(ioutil.Discard)
|
||||||
configDetails, err := getConfigDetails(opts.Composefiles, appEnv)
|
|
||||||
if err != nil {
|
var projectOptions *composeGoCli.ProjectOptions
|
||||||
return nil, err
|
if len(conf.ComposeFiles) == 0 {
|
||||||
|
return project, errors.New(i18n.G("LoadCompose: provide compose files"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if options == nil {
|
if len(conf.AppEnv) == 0 {
|
||||||
options = []func(*loader.Options){DontSkipValidation}
|
var err error
|
||||||
}
|
projectOptions, err = composeGoCli.NewProjectOptions(
|
||||||
|
conf.ComposeFiles,
|
||||||
dicts := getDictsFrom(configDetails.ConfigFiles)
|
composeGoCli.WithInterpolation(false),
|
||||||
config, err := loader.Load(configDetails, options...)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if fpe, ok := err.(*loader.ForbiddenPropertiesError); ok {
|
return project, err
|
||||||
return nil, errors.New(i18n.G("compose file contains unsupported options: %s", propertyWarnings(fpe.Properties)))
|
}
|
||||||
|
} else {
|
||||||
|
var env []string
|
||||||
|
for k, v := range conf.AppEnv {
|
||||||
|
env = append(env, fmt.Sprintf("%s=%s", k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
projectOptions, err = composeGoCli.NewProjectOptions(
|
||||||
|
conf.ComposeFiles,
|
||||||
|
composeGoCli.WithEnv(env),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return project, err
|
||||||
}
|
}
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recipeName, exists := appEnv["RECIPE"]
|
project, err := projectOptions.LoadProject(context.Background())
|
||||||
if !exists {
|
if err != nil {
|
||||||
recipeName, _ = appEnv["TYPE"]
|
return project, err
|
||||||
}
|
}
|
||||||
|
|
||||||
unsupportedProperties := loader.GetUnsupportedProperties(dicts...)
|
return project, nil
|
||||||
if len(unsupportedProperties) > 0 {
|
|
||||||
log.Warn(i18n.G("%s: ignoring unsupported options: %s", recipeName, strings.Join(unsupportedProperties, ", ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecatedProperties := loader.GetDeprecatedProperties(dicts...)
|
|
||||||
if len(deprecatedProperties) > 0 {
|
|
||||||
log.Warn(i18n.G("%s: ignoring deprecated options: %s", recipeName, propertyWarnings(deprecatedProperties)))
|
|
||||||
}
|
|
||||||
return config, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDictsFrom(configFiles []composetypes.ConfigFile) []map[string]interface{} {
|
func getDictsFrom(configFiles []composetypes.ConfigFile) []map[string]interface{} {
|
||||||
@ -138,7 +143,7 @@ func loadConfigFile(filename string) (*composetypes.ConfigFile, error) {
|
|||||||
|
|
||||||
config, err := loader.ParseYAML(bytes)
|
config, err := loader.ParseYAML(bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("%s: %s", filename, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &composetypes.ConfigFile{
|
return &composetypes.ConfigFile{
|
||||||
|
|||||||
26
pkg/upstream/stack/loader_test.go
Normal file
26
pkg/upstream/stack/loader_test.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package stack_test // https://github.com/docker/cli/blob/master/cli/command/stack/loader/loader.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"coopcloud.tech/abra/pkg/app"
|
||||||
|
"coopcloud.tech/abra/pkg/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSkipInterpolation(t *testing.T) {
|
||||||
|
test.Setup()
|
||||||
|
t.Cleanup(func() { test.Teardown() })
|
||||||
|
|
||||||
|
a, err := app.Get(test.AppName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = a.Recipe.GetComposeConfig()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: ensure compose has a port with no interpolated value
|
||||||
|
// TODO: ensure compose has port with interpolated value
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@ import (
|
|||||||
stdlibErr "errors"
|
stdlibErr "errors"
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
composeGoTypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
|
|
||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"coopcloud.tech/abra/pkg/i18n"
|
"coopcloud.tech/abra/pkg/i18n"
|
||||||
@ -20,7 +21,6 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/upstream/convert"
|
"coopcloud.tech/abra/pkg/upstream/convert"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/stack/formatter"
|
"github.com/docker/cli/cli/command/stack/formatter"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
@ -197,7 +197,7 @@ func pruneServices(ctx context.Context, cl *dockerClient.Client, namespace conve
|
|||||||
func RunDeploy(
|
func RunDeploy(
|
||||||
cl *dockerClient.Client,
|
cl *dockerClient.Client,
|
||||||
opts Deploy,
|
opts Deploy,
|
||||||
cfg *composetypes.Config,
|
cfg *composeGoTypes.Project,
|
||||||
appName string,
|
appName string,
|
||||||
serverName string,
|
serverName string,
|
||||||
dontWait bool,
|
dontWait bool,
|
||||||
@ -246,7 +246,7 @@ func deployCompose(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
cl *dockerClient.Client,
|
cl *dockerClient.Client,
|
||||||
opts Deploy,
|
opts Deploy,
|
||||||
config *composetypes.Config,
|
config *composeGoTypes.Project,
|
||||||
appName string,
|
appName string,
|
||||||
serverName string,
|
serverName string,
|
||||||
dontWait bool,
|
dontWait bool,
|
||||||
@ -325,7 +325,7 @@ func deployCompose(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getServicesDeclaredNetworks(serviceConfigs []composetypes.ServiceConfig) map[string]struct{} {
|
func getServicesDeclaredNetworks(serviceConfigs map[string]composeGoTypes.ServiceConfig) map[string]struct{} {
|
||||||
serviceNetworks := map[string]struct{}{}
|
serviceNetworks := map[string]struct{}{}
|
||||||
for _, serviceConfig := range serviceConfigs {
|
for _, serviceConfig := range serviceConfigs {
|
||||||
if len(serviceConfig.Networks) == 0 {
|
if len(serviceConfig.Networks) == 0 {
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
"gomodTidy"
|
"gomodTidy"
|
||||||
],
|
],
|
||||||
"ignoreDeps": [
|
"ignoreDeps": [
|
||||||
"github.com/urfave/cli",
|
"github.com/docker/cli",
|
||||||
"goreleaser/goreleaser"
|
"github.com/spf13/cobra"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,7 +50,7 @@ echo "========================================================================"
|
|||||||
echo "========================================================================"
|
echo "========================================================================"
|
||||||
echo "BUILDING ABRA"
|
echo "BUILDING ABRA"
|
||||||
echo "========================================================================"
|
echo "========================================================================"
|
||||||
export PATH="/usr/lib/go-1.21/bin:$PATH"
|
export PATH="$PATH:/usr/local/go/bin"
|
||||||
make build
|
make build
|
||||||
echo "========================================================================"
|
echo "========================================================================"
|
||||||
|
|
||||||
|
|||||||
@ -217,3 +217,53 @@ teardown() {
|
|||||||
assert_failure
|
assert_failure
|
||||||
assert_output --partial "automagic insertion not supported yet"
|
assert_output --partial "automagic insertion not supported yet"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "push during release fails" {
|
||||||
|
tagHash=$(_get_tag_hash "0.2.0+1.21.0")
|
||||||
|
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" checkout "$tagHash"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run $ABRA recipe upgrade "$TEST_RECIPE" --no-input --patch --commit
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" show
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'image: nginx:1.21.6'
|
||||||
|
|
||||||
|
wantHash="$(_get_current_hash)"
|
||||||
|
|
||||||
|
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" remote set-url origin-ssh "$ABRA_DIR/does/not/exist"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run $ABRA recipe release "$TEST_RECIPE" --no-input --patch
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial 'failed to publish new release:'
|
||||||
|
assert_output --partial 'any changes made have been reverted'
|
||||||
|
|
||||||
|
assert_equal "$wantHash" "$(_get_current_hash)"
|
||||||
|
|
||||||
|
assert_equal "$(_git_status)" ""
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "release, fail, release: works" {
|
||||||
|
tagHash=$(_get_tag_hash "0.2.0+1.21.0")
|
||||||
|
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" checkout "$tagHash"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run $ABRA recipe upgrade "$TEST_RECIPE" --no-input --patch --commit
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
# NOTE(d1): fake broken remote so the release fails
|
||||||
|
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" remote set-url origin-ssh "$ABRA_DIR/does/not/exist"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run $ABRA recipe release "$TEST_RECIPE" --no-input --patch
|
||||||
|
assert_failure
|
||||||
|
|
||||||
|
# NOTE(d1): correct remote so release can proceed
|
||||||
|
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" remote set-url origin-ssh "$ABRA_DIR/origin-recipes/$TEST_RECIPE.git"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run $ABRA recipe release "$TEST_RECIPE" --no-input --patch
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
RECIPE=test_recipe
|
RECIPE=test_recipe
|
||||||
DOMAIN=test_app.example.com
|
DOMAIN=test_app.example.com
|
||||||
|
|
||||||
# NOTE(d1): ensure commented out TIMEOUT doesn't get included
|
#
|
||||||
# see TestReadEnv in ./pkg/envfile
|
# NOTE(d1): for new changes, you *MUST* also update ../test_server/test_app.example.com.env
|
||||||
# TIMEOUT=120
|
#
|
||||||
|
|
||||||
|
# NOTE(d1): TestReadEnv
|
||||||
|
# FOO=BAR
|
||||||
|
|||||||
7
tests/resources/test_recipe/compose.interpolate.yml
Normal file
7
tests/resources/test_recipe/compose.interpolate.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
ports:
|
||||||
|
- target: 22
|
||||||
|
published: ${PORT}
|
||||||
@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
version: "3.8"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
@ -8,6 +7,7 @@ services:
|
|||||||
- proxy
|
- proxy
|
||||||
deploy:
|
deploy:
|
||||||
labels:
|
labels:
|
||||||
|
- "coop-cloud.${STACK_NAME}.version=0.1.0+0.1.0"
|
||||||
- "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT}"
|
- "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT}"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
RECIPE=test_recipe
|
RECIPE=test_recipe
|
||||||
DOMAIN=test_app.example.com
|
DOMAIN=test_app.example.com
|
||||||
|
|
||||||
# NOTE(d1): ensure commented out TIMEOUT doesn't get included
|
#
|
||||||
# see TestReadEnv in ./pkg/envfile
|
# NOTE(d1): for new changes, you *MUST* also update ../test_recipe/.env.sample
|
||||||
# TIMEOUT=120
|
#
|
||||||
|
|
||||||
|
# NOTE(d1): TestReadEnv
|
||||||
|
# FOO=BAR
|
||||||
|
|||||||
2
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
2
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
@ -1,7 +1,7 @@
|
|||||||
TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
|
TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
|
||||||
reflection interface similar to Go's standard library `json` and `xml` packages.
|
reflection interface similar to Go's standard library `json` and `xml` packages.
|
||||||
|
|
||||||
Compatible with TOML version [v1.0.0](https://toml.io/en/v1.0.0).
|
Compatible with TOML version [v1.1.0](https://toml.io/en/v1.1.0).
|
||||||
|
|
||||||
Documentation: https://pkg.go.dev/github.com/BurntSushi/toml
|
Documentation: https://pkg.go.dev/github.com/BurntSushi/toml
|
||||||
|
|
||||||
|
|||||||
9
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
9
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
@ -206,6 +206,13 @@ func markDecodedRecursive(md *MetaData, tmap map[string]any) {
|
|||||||
markDecodedRecursive(md, tmap)
|
markDecodedRecursive(md, tmap)
|
||||||
md.context = md.context[0 : len(md.context)-1]
|
md.context = md.context[0 : len(md.context)-1]
|
||||||
}
|
}
|
||||||
|
if tarr, ok := tmap[key].([]map[string]any); ok {
|
||||||
|
for _, elm := range tarr {
|
||||||
|
md.context = append(md.context, key)
|
||||||
|
markDecodedRecursive(md, elm)
|
||||||
|
md.context = md.context[0 : len(md.context)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +430,7 @@ func (md *MetaData) unifyString(data any, rv reflect.Value) error {
|
|||||||
if i, ok := data.(int64); ok {
|
if i, ok := data.(int64); ok {
|
||||||
rv.SetString(strconv.FormatInt(i, 10))
|
rv.SetString(strconv.FormatInt(i, 10))
|
||||||
} else if f, ok := data.(float64); ok {
|
} else if f, ok := data.(float64); ok {
|
||||||
rv.SetString(strconv.FormatFloat(f, 'f', -1, 64))
|
rv.SetString(strconv.FormatFloat(f, 'g', -1, 64))
|
||||||
} else {
|
} else {
|
||||||
return md.badtype("string", data)
|
return md.badtype("string", data)
|
||||||
}
|
}
|
||||||
|
|||||||
79
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
79
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
@ -228,9 +228,9 @@ func (enc *Encoder) eElement(rv reflect.Value) {
|
|||||||
}
|
}
|
||||||
switch v.Location() {
|
switch v.Location() {
|
||||||
default:
|
default:
|
||||||
enc.wf(v.Format(format))
|
enc.write(v.Format(format))
|
||||||
case internal.LocalDatetime, internal.LocalDate, internal.LocalTime:
|
case internal.LocalDatetime, internal.LocalDate, internal.LocalTime:
|
||||||
enc.wf(v.In(time.UTC).Format(format))
|
enc.write(v.In(time.UTC).Format(format))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case Marshaler:
|
case Marshaler:
|
||||||
@ -279,40 +279,40 @@ func (enc *Encoder) eElement(rv reflect.Value) {
|
|||||||
case reflect.String:
|
case reflect.String:
|
||||||
enc.writeQuoted(rv.String())
|
enc.writeQuoted(rv.String())
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
enc.wf(strconv.FormatBool(rv.Bool()))
|
enc.write(strconv.FormatBool(rv.Bool()))
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
enc.wf(strconv.FormatInt(rv.Int(), 10))
|
enc.write(strconv.FormatInt(rv.Int(), 10))
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
enc.wf(strconv.FormatUint(rv.Uint(), 10))
|
enc.write(strconv.FormatUint(rv.Uint(), 10))
|
||||||
case reflect.Float32:
|
case reflect.Float32:
|
||||||
f := rv.Float()
|
f := rv.Float()
|
||||||
if math.IsNaN(f) {
|
if math.IsNaN(f) {
|
||||||
if math.Signbit(f) {
|
if math.Signbit(f) {
|
||||||
enc.wf("-")
|
enc.write("-")
|
||||||
}
|
}
|
||||||
enc.wf("nan")
|
enc.write("nan")
|
||||||
} else if math.IsInf(f, 0) {
|
} else if math.IsInf(f, 0) {
|
||||||
if math.Signbit(f) {
|
if math.Signbit(f) {
|
||||||
enc.wf("-")
|
enc.write("-")
|
||||||
}
|
}
|
||||||
enc.wf("inf")
|
enc.write("inf")
|
||||||
} else {
|
} else {
|
||||||
enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 32)))
|
enc.write(floatAddDecimal(strconv.FormatFloat(f, 'g', -1, 32)))
|
||||||
}
|
}
|
||||||
case reflect.Float64:
|
case reflect.Float64:
|
||||||
f := rv.Float()
|
f := rv.Float()
|
||||||
if math.IsNaN(f) {
|
if math.IsNaN(f) {
|
||||||
if math.Signbit(f) {
|
if math.Signbit(f) {
|
||||||
enc.wf("-")
|
enc.write("-")
|
||||||
}
|
}
|
||||||
enc.wf("nan")
|
enc.write("nan")
|
||||||
} else if math.IsInf(f, 0) {
|
} else if math.IsInf(f, 0) {
|
||||||
if math.Signbit(f) {
|
if math.Signbit(f) {
|
||||||
enc.wf("-")
|
enc.write("-")
|
||||||
}
|
}
|
||||||
enc.wf("inf")
|
enc.write("inf")
|
||||||
} else {
|
} else {
|
||||||
enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 64)))
|
enc.write(floatAddDecimal(strconv.FormatFloat(f, 'g', -1, 64)))
|
||||||
}
|
}
|
||||||
case reflect.Array, reflect.Slice:
|
case reflect.Array, reflect.Slice:
|
||||||
enc.eArrayOrSliceElement(rv)
|
enc.eArrayOrSliceElement(rv)
|
||||||
@ -330,27 +330,32 @@ func (enc *Encoder) eElement(rv reflect.Value) {
|
|||||||
// By the TOML spec, all floats must have a decimal with at least one number on
|
// By the TOML spec, all floats must have a decimal with at least one number on
|
||||||
// either side.
|
// either side.
|
||||||
func floatAddDecimal(fstr string) string {
|
func floatAddDecimal(fstr string) string {
|
||||||
if !strings.Contains(fstr, ".") {
|
for _, c := range fstr {
|
||||||
return fstr + ".0"
|
if c == 'e' { // Exponent syntax
|
||||||
|
return fstr
|
||||||
|
}
|
||||||
|
if c == '.' {
|
||||||
|
return fstr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return fstr
|
return fstr + ".0"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (enc *Encoder) writeQuoted(s string) {
|
func (enc *Encoder) writeQuoted(s string) {
|
||||||
enc.wf("\"%s\"", dblQuotedReplacer.Replace(s))
|
enc.write(`"` + dblQuotedReplacer.Replace(s) + `"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
|
func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
|
||||||
length := rv.Len()
|
length := rv.Len()
|
||||||
enc.wf("[")
|
enc.write("[")
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
elem := eindirect(rv.Index(i))
|
elem := eindirect(rv.Index(i))
|
||||||
enc.eElement(elem)
|
enc.eElement(elem)
|
||||||
if i != length-1 {
|
if i != length-1 {
|
||||||
enc.wf(", ")
|
enc.write(", ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enc.wf("]")
|
enc.write("]")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
|
func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
|
||||||
@ -363,7 +368,7 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
enc.newline()
|
enc.newline()
|
||||||
enc.wf("%s[[%s]]", enc.indentStr(key), key)
|
enc.writef("%s[[%s]]", enc.indentStr(key), key)
|
||||||
enc.newline()
|
enc.newline()
|
||||||
enc.eMapOrStruct(key, trv, false)
|
enc.eMapOrStruct(key, trv, false)
|
||||||
}
|
}
|
||||||
@ -376,7 +381,7 @@ func (enc *Encoder) eTable(key Key, rv reflect.Value) {
|
|||||||
enc.newline()
|
enc.newline()
|
||||||
}
|
}
|
||||||
if len(key) > 0 {
|
if len(key) > 0 {
|
||||||
enc.wf("%s[%s]", enc.indentStr(key), key)
|
enc.writef("%s[%s]", enc.indentStr(key), key)
|
||||||
enc.newline()
|
enc.newline()
|
||||||
}
|
}
|
||||||
enc.eMapOrStruct(key, rv, false)
|
enc.eMapOrStruct(key, rv, false)
|
||||||
@ -422,7 +427,7 @@ func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) {
|
|||||||
if inline {
|
if inline {
|
||||||
enc.writeKeyValue(Key{mapKey.String()}, val, true)
|
enc.writeKeyValue(Key{mapKey.String()}, val, true)
|
||||||
if trailC || i != len(mapKeys)-1 {
|
if trailC || i != len(mapKeys)-1 {
|
||||||
enc.wf(", ")
|
enc.write(", ")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
enc.encode(key.add(mapKey.String()), val)
|
enc.encode(key.add(mapKey.String()), val)
|
||||||
@ -431,12 +436,12 @@ func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if inline {
|
if inline {
|
||||||
enc.wf("{")
|
enc.write("{")
|
||||||
}
|
}
|
||||||
writeMapKeys(mapKeysDirect, len(mapKeysSub) > 0)
|
writeMapKeys(mapKeysDirect, len(mapKeysSub) > 0)
|
||||||
writeMapKeys(mapKeysSub, false)
|
writeMapKeys(mapKeysSub, false)
|
||||||
if inline {
|
if inline {
|
||||||
enc.wf("}")
|
enc.write("}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,7 +539,7 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
|
|||||||
if inline {
|
if inline {
|
||||||
enc.writeKeyValue(Key{keyName}, fieldVal, true)
|
enc.writeKeyValue(Key{keyName}, fieldVal, true)
|
||||||
if fieldIndex[0] != totalFields-1 {
|
if fieldIndex[0] != totalFields-1 {
|
||||||
enc.wf(", ")
|
enc.write(", ")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
enc.encode(key.add(keyName), fieldVal)
|
enc.encode(key.add(keyName), fieldVal)
|
||||||
@ -543,14 +548,14 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if inline {
|
if inline {
|
||||||
enc.wf("{")
|
enc.write("{")
|
||||||
}
|
}
|
||||||
|
|
||||||
l := len(fieldsDirect) + len(fieldsSub)
|
l := len(fieldsDirect) + len(fieldsSub)
|
||||||
writeFields(fieldsDirect, l)
|
writeFields(fieldsDirect, l)
|
||||||
writeFields(fieldsSub, l)
|
writeFields(fieldsSub, l)
|
||||||
if inline {
|
if inline {
|
||||||
enc.wf("}")
|
enc.write("}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,7 +705,7 @@ func isEmpty(rv reflect.Value) bool {
|
|||||||
|
|
||||||
func (enc *Encoder) newline() {
|
func (enc *Encoder) newline() {
|
||||||
if enc.hasWritten {
|
if enc.hasWritten {
|
||||||
enc.wf("\n")
|
enc.write("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,14 +727,22 @@ func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) {
|
|||||||
enc.eElement(val)
|
enc.eElement(val)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
|
enc.writef("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
|
||||||
enc.eElement(val)
|
enc.eElement(val)
|
||||||
if !inline {
|
if !inline {
|
||||||
enc.newline()
|
enc.newline()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (enc *Encoder) wf(format string, v ...any) {
|
func (enc *Encoder) write(s string) {
|
||||||
|
_, err := enc.w.WriteString(s)
|
||||||
|
if err != nil {
|
||||||
|
encPanic(err)
|
||||||
|
}
|
||||||
|
enc.hasWritten = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) writef(format string, v ...any) {
|
||||||
_, err := fmt.Fprintf(enc.w, format, v...)
|
_, err := fmt.Fprintf(enc.w, format, v...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
encPanic(err)
|
encPanic(err)
|
||||||
|
|||||||
130
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
130
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
@ -13,7 +13,6 @@ type itemType int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
itemError itemType = iota
|
itemError itemType = iota
|
||||||
itemNIL // used in the parser to indicate no type
|
|
||||||
itemEOF
|
itemEOF
|
||||||
itemText
|
itemText
|
||||||
itemString
|
itemString
|
||||||
@ -47,14 +46,13 @@ func (p Position) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type lexer struct {
|
type lexer struct {
|
||||||
input string
|
input string
|
||||||
start int
|
start int
|
||||||
pos int
|
pos int
|
||||||
line int
|
line int
|
||||||
state stateFn
|
state stateFn
|
||||||
items chan item
|
items chan item
|
||||||
tomlNext bool
|
esc bool
|
||||||
esc bool
|
|
||||||
|
|
||||||
// Allow for backing up up to 4 runes. This is necessary because TOML
|
// Allow for backing up up to 4 runes. This is necessary because TOML
|
||||||
// contains 3-rune tokens (""" and ''').
|
// contains 3-rune tokens (""" and ''').
|
||||||
@ -90,14 +88,13 @@ func (lx *lexer) nextItem() item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func lex(input string, tomlNext bool) *lexer {
|
func lex(input string) *lexer {
|
||||||
lx := &lexer{
|
lx := &lexer{
|
||||||
input: input,
|
input: input,
|
||||||
state: lexTop,
|
state: lexTop,
|
||||||
items: make(chan item, 10),
|
items: make(chan item, 10),
|
||||||
stack: make([]stateFn, 0, 10),
|
stack: make([]stateFn, 0, 10),
|
||||||
line: 1,
|
line: 1,
|
||||||
tomlNext: tomlNext,
|
|
||||||
}
|
}
|
||||||
return lx
|
return lx
|
||||||
}
|
}
|
||||||
@ -108,7 +105,7 @@ func (lx *lexer) push(state stateFn) {
|
|||||||
|
|
||||||
func (lx *lexer) pop() stateFn {
|
func (lx *lexer) pop() stateFn {
|
||||||
if len(lx.stack) == 0 {
|
if len(lx.stack) == 0 {
|
||||||
return lx.errorf("BUG in lexer: no states to pop")
|
panic("BUG in lexer: no states to pop")
|
||||||
}
|
}
|
||||||
last := lx.stack[len(lx.stack)-1]
|
last := lx.stack[len(lx.stack)-1]
|
||||||
lx.stack = lx.stack[0 : len(lx.stack)-1]
|
lx.stack = lx.stack[0 : len(lx.stack)-1]
|
||||||
@ -305,6 +302,8 @@ func lexTop(lx *lexer) stateFn {
|
|||||||
return lexTableStart
|
return lexTableStart
|
||||||
case eof:
|
case eof:
|
||||||
if lx.pos > lx.start {
|
if lx.pos > lx.start {
|
||||||
|
// TODO: never reached? I think this can only occur on a bug in the
|
||||||
|
// lexer(?)
|
||||||
return lx.errorf("unexpected EOF")
|
return lx.errorf("unexpected EOF")
|
||||||
}
|
}
|
||||||
lx.emit(itemEOF)
|
lx.emit(itemEOF)
|
||||||
@ -392,8 +391,6 @@ func lexTableNameStart(lx *lexer) stateFn {
|
|||||||
func lexTableNameEnd(lx *lexer) stateFn {
|
func lexTableNameEnd(lx *lexer) stateFn {
|
||||||
lx.skip(isWhitespace)
|
lx.skip(isWhitespace)
|
||||||
switch r := lx.next(); {
|
switch r := lx.next(); {
|
||||||
case isWhitespace(r):
|
|
||||||
return lexTableNameEnd
|
|
||||||
case r == '.':
|
case r == '.':
|
||||||
lx.ignore()
|
lx.ignore()
|
||||||
return lexTableNameStart
|
return lexTableNameStart
|
||||||
@ -412,7 +409,7 @@ func lexTableNameEnd(lx *lexer) stateFn {
|
|||||||
// Lexes only one part, e.g. only 'a' inside 'a.b'.
|
// Lexes only one part, e.g. only 'a' inside 'a.b'.
|
||||||
func lexBareName(lx *lexer) stateFn {
|
func lexBareName(lx *lexer) stateFn {
|
||||||
r := lx.next()
|
r := lx.next()
|
||||||
if isBareKeyChar(r, lx.tomlNext) {
|
if isBareKeyChar(r) {
|
||||||
return lexBareName
|
return lexBareName
|
||||||
}
|
}
|
||||||
lx.backup()
|
lx.backup()
|
||||||
@ -420,23 +417,23 @@ func lexBareName(lx *lexer) stateFn {
|
|||||||
return lx.pop()
|
return lx.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// lexBareName lexes one part of a key or table.
|
// lexQuotedName lexes one part of a quoted key or table name. It assumes that
|
||||||
//
|
// it starts lexing at the quote itself (" or ').
|
||||||
// It assumes that at least one valid character for the table has already been
|
|
||||||
// read.
|
|
||||||
//
|
//
|
||||||
// Lexes only one part, e.g. only '"a"' inside '"a".b'.
|
// Lexes only one part, e.g. only '"a"' inside '"a".b'.
|
||||||
func lexQuotedName(lx *lexer) stateFn {
|
func lexQuotedName(lx *lexer) stateFn {
|
||||||
r := lx.next()
|
r := lx.next()
|
||||||
switch {
|
switch {
|
||||||
case isWhitespace(r):
|
|
||||||
return lexSkip(lx, lexValue)
|
|
||||||
case r == '"':
|
case r == '"':
|
||||||
lx.ignore() // ignore the '"'
|
lx.ignore() // ignore the '"'
|
||||||
return lexString
|
return lexString
|
||||||
case r == '\'':
|
case r == '\'':
|
||||||
lx.ignore() // ignore the "'"
|
lx.ignore() // ignore the "'"
|
||||||
return lexRawString
|
return lexRawString
|
||||||
|
|
||||||
|
// TODO: I don't think any of the below conditions can ever be reached?
|
||||||
|
case isWhitespace(r):
|
||||||
|
return lexSkip(lx, lexValue)
|
||||||
case r == eof:
|
case r == eof:
|
||||||
return lx.errorf("unexpected EOF; expected value")
|
return lx.errorf("unexpected EOF; expected value")
|
||||||
default:
|
default:
|
||||||
@ -464,17 +461,19 @@ func lexKeyStart(lx *lexer) stateFn {
|
|||||||
func lexKeyNameStart(lx *lexer) stateFn {
|
func lexKeyNameStart(lx *lexer) stateFn {
|
||||||
lx.skip(isWhitespace)
|
lx.skip(isWhitespace)
|
||||||
switch r := lx.peek(); {
|
switch r := lx.peek(); {
|
||||||
case r == '=' || r == eof:
|
default:
|
||||||
return lx.errorf("unexpected '='")
|
lx.push(lexKeyEnd)
|
||||||
case r == '.':
|
return lexBareName
|
||||||
return lx.errorf("unexpected '.'")
|
|
||||||
case r == '"' || r == '\'':
|
case r == '"' || r == '\'':
|
||||||
lx.ignore()
|
lx.ignore()
|
||||||
lx.push(lexKeyEnd)
|
lx.push(lexKeyEnd)
|
||||||
return lexQuotedName
|
return lexQuotedName
|
||||||
default:
|
|
||||||
lx.push(lexKeyEnd)
|
// TODO: I think these can never be reached?
|
||||||
return lexBareName
|
case r == '=' || r == eof:
|
||||||
|
return lx.errorf("unexpected '='")
|
||||||
|
case r == '.':
|
||||||
|
return lx.errorf("unexpected '.'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,7 +484,7 @@ func lexKeyEnd(lx *lexer) stateFn {
|
|||||||
switch r := lx.next(); {
|
switch r := lx.next(); {
|
||||||
case isWhitespace(r):
|
case isWhitespace(r):
|
||||||
return lexSkip(lx, lexKeyEnd)
|
return lexSkip(lx, lexKeyEnd)
|
||||||
case r == eof:
|
case r == eof: // TODO: never reached
|
||||||
return lx.errorf("unexpected EOF; expected key separator '='")
|
return lx.errorf("unexpected EOF; expected key separator '='")
|
||||||
case r == '.':
|
case r == '.':
|
||||||
lx.ignore()
|
lx.ignore()
|
||||||
@ -628,10 +627,7 @@ func lexInlineTableValue(lx *lexer) stateFn {
|
|||||||
case isWhitespace(r):
|
case isWhitespace(r):
|
||||||
return lexSkip(lx, lexInlineTableValue)
|
return lexSkip(lx, lexInlineTableValue)
|
||||||
case isNL(r):
|
case isNL(r):
|
||||||
if lx.tomlNext {
|
return lexSkip(lx, lexInlineTableValue)
|
||||||
return lexSkip(lx, lexInlineTableValue)
|
|
||||||
}
|
|
||||||
return lx.errorPrevLine(errLexInlineTableNL{})
|
|
||||||
case r == '#':
|
case r == '#':
|
||||||
lx.push(lexInlineTableValue)
|
lx.push(lexInlineTableValue)
|
||||||
return lexCommentStart
|
return lexCommentStart
|
||||||
@ -653,10 +649,7 @@ func lexInlineTableValueEnd(lx *lexer) stateFn {
|
|||||||
case isWhitespace(r):
|
case isWhitespace(r):
|
||||||
return lexSkip(lx, lexInlineTableValueEnd)
|
return lexSkip(lx, lexInlineTableValueEnd)
|
||||||
case isNL(r):
|
case isNL(r):
|
||||||
if lx.tomlNext {
|
return lexSkip(lx, lexInlineTableValueEnd)
|
||||||
return lexSkip(lx, lexInlineTableValueEnd)
|
|
||||||
}
|
|
||||||
return lx.errorPrevLine(errLexInlineTableNL{})
|
|
||||||
case r == '#':
|
case r == '#':
|
||||||
lx.push(lexInlineTableValueEnd)
|
lx.push(lexInlineTableValueEnd)
|
||||||
return lexCommentStart
|
return lexCommentStart
|
||||||
@ -664,10 +657,7 @@ func lexInlineTableValueEnd(lx *lexer) stateFn {
|
|||||||
lx.ignore()
|
lx.ignore()
|
||||||
lx.skip(isWhitespace)
|
lx.skip(isWhitespace)
|
||||||
if lx.peek() == '}' {
|
if lx.peek() == '}' {
|
||||||
if lx.tomlNext {
|
return lexInlineTableValueEnd
|
||||||
return lexInlineTableValueEnd
|
|
||||||
}
|
|
||||||
return lx.errorf("trailing comma not allowed in inline tables")
|
|
||||||
}
|
}
|
||||||
return lexInlineTableValue
|
return lexInlineTableValue
|
||||||
case r == '}':
|
case r == '}':
|
||||||
@ -855,9 +845,6 @@ func lexStringEscape(lx *lexer) stateFn {
|
|||||||
r := lx.next()
|
r := lx.next()
|
||||||
switch r {
|
switch r {
|
||||||
case 'e':
|
case 'e':
|
||||||
if !lx.tomlNext {
|
|
||||||
return lx.error(errLexEscape{r})
|
|
||||||
}
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case 'b':
|
case 'b':
|
||||||
fallthrough
|
fallthrough
|
||||||
@ -878,9 +865,6 @@ func lexStringEscape(lx *lexer) stateFn {
|
|||||||
case '\\':
|
case '\\':
|
||||||
return lx.pop()
|
return lx.pop()
|
||||||
case 'x':
|
case 'x':
|
||||||
if !lx.tomlNext {
|
|
||||||
return lx.error(errLexEscape{r})
|
|
||||||
}
|
|
||||||
return lexHexEscape
|
return lexHexEscape
|
||||||
case 'u':
|
case 'u':
|
||||||
return lexShortUnicodeEscape
|
return lexShortUnicodeEscape
|
||||||
@ -928,19 +912,9 @@ func lexLongUnicodeEscape(lx *lexer) stateFn {
|
|||||||
// lexBaseNumberOrDate can differentiate base prefixed integers from other
|
// lexBaseNumberOrDate can differentiate base prefixed integers from other
|
||||||
// types.
|
// types.
|
||||||
func lexNumberOrDateStart(lx *lexer) stateFn {
|
func lexNumberOrDateStart(lx *lexer) stateFn {
|
||||||
r := lx.next()
|
if lx.next() == '0' {
|
||||||
switch r {
|
|
||||||
case '0':
|
|
||||||
return lexBaseNumberOrDate
|
return lexBaseNumberOrDate
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isDigit(r) {
|
|
||||||
// The only way to reach this state is if the value starts
|
|
||||||
// with a digit, so specifically treat anything else as an
|
|
||||||
// error.
|
|
||||||
return lx.errorf("expected a digit but got %q", r)
|
|
||||||
}
|
|
||||||
|
|
||||||
return lexNumberOrDate
|
return lexNumberOrDate
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1196,13 +1170,13 @@ func lexSkip(lx *lexer, nextState stateFn) stateFn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s stateFn) String() string {
|
func (s stateFn) String() string {
|
||||||
|
if s == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
name := runtime.FuncForPC(reflect.ValueOf(s).Pointer()).Name()
|
name := runtime.FuncForPC(reflect.ValueOf(s).Pointer()).Name()
|
||||||
if i := strings.LastIndexByte(name, '.'); i > -1 {
|
if i := strings.LastIndexByte(name, '.'); i > -1 {
|
||||||
name = name[i+1:]
|
name = name[i+1:]
|
||||||
}
|
}
|
||||||
if s == nil {
|
|
||||||
name = "<nil>"
|
|
||||||
}
|
|
||||||
return name + "()"
|
return name + "()"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1210,8 +1184,6 @@ func (itype itemType) String() string {
|
|||||||
switch itype {
|
switch itype {
|
||||||
case itemError:
|
case itemError:
|
||||||
return "Error"
|
return "Error"
|
||||||
case itemNIL:
|
|
||||||
return "NIL"
|
|
||||||
case itemEOF:
|
case itemEOF:
|
||||||
return "EOF"
|
return "EOF"
|
||||||
case itemText:
|
case itemText:
|
||||||
@ -1226,18 +1198,22 @@ func (itype itemType) String() string {
|
|||||||
return "Float"
|
return "Float"
|
||||||
case itemDatetime:
|
case itemDatetime:
|
||||||
return "DateTime"
|
return "DateTime"
|
||||||
case itemTableStart:
|
|
||||||
return "TableStart"
|
|
||||||
case itemTableEnd:
|
|
||||||
return "TableEnd"
|
|
||||||
case itemKeyStart:
|
|
||||||
return "KeyStart"
|
|
||||||
case itemKeyEnd:
|
|
||||||
return "KeyEnd"
|
|
||||||
case itemArray:
|
case itemArray:
|
||||||
return "Array"
|
return "Array"
|
||||||
case itemArrayEnd:
|
case itemArrayEnd:
|
||||||
return "ArrayEnd"
|
return "ArrayEnd"
|
||||||
|
case itemTableStart:
|
||||||
|
return "TableStart"
|
||||||
|
case itemTableEnd:
|
||||||
|
return "TableEnd"
|
||||||
|
case itemArrayTableStart:
|
||||||
|
return "ArrayTableStart"
|
||||||
|
case itemArrayTableEnd:
|
||||||
|
return "ArrayTableEnd"
|
||||||
|
case itemKeyStart:
|
||||||
|
return "KeyStart"
|
||||||
|
case itemKeyEnd:
|
||||||
|
return "KeyEnd"
|
||||||
case itemCommentStart:
|
case itemCommentStart:
|
||||||
return "CommentStart"
|
return "CommentStart"
|
||||||
case itemInlineTableStart:
|
case itemInlineTableStart:
|
||||||
@ -1266,7 +1242,7 @@ func isDigit(r rune) bool { return r >= '0' && r <= '9' }
|
|||||||
func isBinary(r rune) bool { return r == '0' || r == '1' }
|
func isBinary(r rune) bool { return r == '0' || r == '1' }
|
||||||
func isOctal(r rune) bool { return r >= '0' && r <= '7' }
|
func isOctal(r rune) bool { return r >= '0' && r <= '7' }
|
||||||
func isHex(r rune) bool { return (r >= '0' && r <= '9') || (r|0x20 >= 'a' && r|0x20 <= 'f') }
|
func isHex(r rune) bool { return (r >= '0' && r <= '9') || (r|0x20 >= 'a' && r|0x20 <= 'f') }
|
||||||
func isBareKeyChar(r rune, tomlNext bool) bool {
|
func isBareKeyChar(r rune) bool {
|
||||||
return (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') ||
|
return (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') ||
|
||||||
(r >= '0' && r <= '9') || r == '_' || r == '-'
|
(r >= '0' && r <= '9') || r == '_' || r == '-'
|
||||||
}
|
}
|
||||||
|
|||||||
46
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
46
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
@ -3,7 +3,6 @@ package toml
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -17,7 +16,6 @@ type parser struct {
|
|||||||
context Key // Full key for the current hash in scope.
|
context Key // Full key for the current hash in scope.
|
||||||
currentKey string // Base key name for everything except hashes.
|
currentKey string // Base key name for everything except hashes.
|
||||||
pos Position // Current position in the TOML file.
|
pos Position // Current position in the TOML file.
|
||||||
tomlNext bool
|
|
||||||
|
|
||||||
ordered []Key // List of keys in the order that they appear in the TOML data.
|
ordered []Key // List of keys in the order that they appear in the TOML data.
|
||||||
|
|
||||||
@ -32,8 +30,6 @@ type keyInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parse(data string) (p *parser, err error) {
|
func parse(data string) (p *parser, err error) {
|
||||||
_, tomlNext := os.LookupEnv("BURNTSUSHI_TOML_110")
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
if pErr, ok := r.(ParseError); ok {
|
if pErr, ok := r.(ParseError); ok {
|
||||||
@ -73,10 +69,9 @@ func parse(data string) (p *parser, err error) {
|
|||||||
p = &parser{
|
p = &parser{
|
||||||
keyInfo: make(map[string]keyInfo),
|
keyInfo: make(map[string]keyInfo),
|
||||||
mapping: make(map[string]any),
|
mapping: make(map[string]any),
|
||||||
lx: lex(data, tomlNext),
|
lx: lex(data),
|
||||||
ordered: make([]Key, 0),
|
ordered: make([]Key, 0),
|
||||||
implicits: make(map[string]struct{}),
|
implicits: make(map[string]struct{}),
|
||||||
tomlNext: tomlNext,
|
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
item := p.next()
|
item := p.next()
|
||||||
@ -350,17 +345,14 @@ func (p *parser) valueFloat(it item) (any, tomlType) {
|
|||||||
var dtTypes = []struct {
|
var dtTypes = []struct {
|
||||||
fmt string
|
fmt string
|
||||||
zone *time.Location
|
zone *time.Location
|
||||||
next bool
|
|
||||||
}{
|
}{
|
||||||
{time.RFC3339Nano, time.Local, false},
|
{time.RFC3339Nano, time.Local},
|
||||||
{"2006-01-02T15:04:05.999999999", internal.LocalDatetime, false},
|
{"2006-01-02T15:04:05.999999999", internal.LocalDatetime},
|
||||||
{"2006-01-02", internal.LocalDate, false},
|
{"2006-01-02", internal.LocalDate},
|
||||||
{"15:04:05.999999999", internal.LocalTime, false},
|
{"15:04:05.999999999", internal.LocalTime},
|
||||||
|
{"2006-01-02T15:04Z07:00", time.Local},
|
||||||
// tomlNext
|
{"2006-01-02T15:04", internal.LocalDatetime},
|
||||||
{"2006-01-02T15:04Z07:00", time.Local, true},
|
{"15:04", internal.LocalTime},
|
||||||
{"2006-01-02T15:04", internal.LocalDatetime, true},
|
|
||||||
{"15:04", internal.LocalTime, true},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) valueDatetime(it item) (any, tomlType) {
|
func (p *parser) valueDatetime(it item) (any, tomlType) {
|
||||||
@ -371,9 +363,6 @@ func (p *parser) valueDatetime(it item) (any, tomlType) {
|
|||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
for _, dt := range dtTypes {
|
for _, dt := range dtTypes {
|
||||||
if dt.next && !p.tomlNext {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone)
|
t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if missingLeadingZero(it.val, dt.fmt) {
|
if missingLeadingZero(it.val, dt.fmt) {
|
||||||
@ -644,6 +633,11 @@ func (p *parser) setValue(key string, value any) {
|
|||||||
// Note that since it has already been defined (as a hash), we don't
|
// Note that since it has already been defined (as a hash), we don't
|
||||||
// want to overwrite it. So our business is done.
|
// want to overwrite it. So our business is done.
|
||||||
if p.isArray(keyContext) {
|
if p.isArray(keyContext) {
|
||||||
|
if !p.isImplicit(keyContext) {
|
||||||
|
if _, ok := hash[key]; ok {
|
||||||
|
p.panicf("Key '%s' has already been defined.", keyContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
p.removeImplicit(keyContext)
|
p.removeImplicit(keyContext)
|
||||||
hash[key] = value
|
hash[key] = value
|
||||||
return
|
return
|
||||||
@ -802,10 +796,8 @@ func (p *parser) replaceEscapes(it item, str string) string {
|
|||||||
b.WriteByte(0x0d)
|
b.WriteByte(0x0d)
|
||||||
skip = 1
|
skip = 1
|
||||||
case 'e':
|
case 'e':
|
||||||
if p.tomlNext {
|
b.WriteByte(0x1b)
|
||||||
b.WriteByte(0x1b)
|
skip = 1
|
||||||
skip = 1
|
|
||||||
}
|
|
||||||
case '"':
|
case '"':
|
||||||
b.WriteByte(0x22)
|
b.WriteByte(0x22)
|
||||||
skip = 1
|
skip = 1
|
||||||
@ -815,11 +807,9 @@ func (p *parser) replaceEscapes(it item, str string) string {
|
|||||||
// The lexer guarantees the correct number of characters are present;
|
// The lexer guarantees the correct number of characters are present;
|
||||||
// don't need to check here.
|
// don't need to check here.
|
||||||
case 'x':
|
case 'x':
|
||||||
if p.tomlNext {
|
escaped := p.asciiEscapeToUnicode(it, str[i+2:i+4])
|
||||||
escaped := p.asciiEscapeToUnicode(it, str[i+2:i+4])
|
b.WriteRune(escaped)
|
||||||
b.WriteRune(escaped)
|
skip = 3
|
||||||
skip = 3
|
|
||||||
}
|
|
||||||
case 'u':
|
case 'u':
|
||||||
escaped := p.asciiEscapeToUnicode(it, str[i+2:i+6])
|
escaped := p.asciiEscapeToUnicode(it, str[i+2:i+6])
|
||||||
b.WriteRune(escaped)
|
b.WriteRune(escaped)
|
||||||
|
|||||||
2
vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go
generated
vendored
2
vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go
generated
vendored
@ -69,6 +69,8 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
|
|||||||
if isPrefix {
|
if isPrefix {
|
||||||
return 0, ArmorCorrupt
|
return 0, ArmorCorrupt
|
||||||
}
|
}
|
||||||
|
// Trim the line to remove any whitespace
|
||||||
|
line = bytes.TrimSpace(line)
|
||||||
|
|
||||||
if bytes.HasPrefix(line, armorEnd) {
|
if bytes.HasPrefix(line, armorEnd) {
|
||||||
l.eof = true
|
l.eof = true
|
||||||
|
|||||||
10
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go
generated
vendored
10
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go
generated
vendored
@ -125,7 +125,10 @@ func (c *curve25519) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecr
|
|||||||
// "VB = convert point V to the octet string"
|
// "VB = convert point V to the octet string"
|
||||||
// sharedPoint corresponds to `VB`.
|
// sharedPoint corresponds to `VB`.
|
||||||
var sharedPoint x25519lib.Key
|
var sharedPoint x25519lib.Key
|
||||||
x25519lib.Shared(&sharedPoint, &ephemeralPrivate, &pubKey)
|
ok := x25519lib.Shared(&sharedPoint, &ephemeralPrivate, &pubKey)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, errors.KeyInvalidError("ecc: the public key is a low order point")
|
||||||
|
}
|
||||||
|
|
||||||
return ephemeralPublic[:], sharedPoint[:], nil
|
return ephemeralPublic[:], sharedPoint[:], nil
|
||||||
}
|
}
|
||||||
@ -146,7 +149,10 @@ func (c *curve25519) Decaps(vsG, secret []byte) (sharedSecret []byte, err error)
|
|||||||
// RFC6637 §8: "Note that the recipient obtains the shared secret by calculating
|
// RFC6637 §8: "Note that the recipient obtains the shared secret by calculating
|
||||||
// S = rV = rvG, where (r,R) is the recipient's key pair."
|
// S = rV = rvG, where (r,R) is the recipient's key pair."
|
||||||
// sharedPoint corresponds to `S`.
|
// sharedPoint corresponds to `S`.
|
||||||
x25519lib.Shared(&sharedPoint, &decodedPrivate, &ephemeralPublic)
|
ok := x25519lib.Shared(&sharedPoint, &decodedPrivate, &ephemeralPublic)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.KeyInvalidError("ecc: the public key is a low order point")
|
||||||
|
}
|
||||||
|
|
||||||
return sharedPoint[:], nil
|
return sharedPoint[:], nil
|
||||||
}
|
}
|
||||||
|
|||||||
5
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go
generated
vendored
5
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go
generated
vendored
@ -78,7 +78,7 @@ func (c *genericCurve) GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err
|
|||||||
func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
|
func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
|
||||||
xP, yP := elliptic.Unmarshal(c.Curve, point)
|
xP, yP := elliptic.Unmarshal(c.Curve, point)
|
||||||
if xP == nil {
|
if xP == nil {
|
||||||
panic("invalid point")
|
return nil, nil, errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
d, x, y, err := elliptic.GenerateKey(c.Curve, rand)
|
d, x, y, err := elliptic.GenerateKey(c.Curve, rand)
|
||||||
@ -99,6 +99,9 @@ func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSe
|
|||||||
|
|
||||||
func (c *genericCurve) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
|
func (c *genericCurve) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
|
||||||
x, y := elliptic.Unmarshal(c.Curve, ephemeral)
|
x, y := elliptic.Unmarshal(c.Curve, ephemeral)
|
||||||
|
if x == nil {
|
||||||
|
return nil, errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
|
||||||
|
}
|
||||||
zbBig, _ := c.Curve.ScalarMult(x, y, secret)
|
zbBig, _ := c.Curve.ScalarMult(x, y, secret)
|
||||||
byteLen := (c.Curve.Params().BitSize + 7) >> 3
|
byteLen := (c.Curve.Params().BitSize + 7) >> 3
|
||||||
zb := make([]byte, byteLen)
|
zb := make([]byte, byteLen)
|
||||||
|
|||||||
26
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
generated
vendored
26
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
generated
vendored
@ -178,6 +178,18 @@ type Config struct {
|
|||||||
// When set to true, a key without flags is treated as if all flags are enabled.
|
// When set to true, a key without flags is treated as if all flags are enabled.
|
||||||
// This behavior is consistent with GPG.
|
// This behavior is consistent with GPG.
|
||||||
InsecureAllowAllKeyFlagsWhenMissing bool
|
InsecureAllowAllKeyFlagsWhenMissing bool
|
||||||
|
// InsecureGenerateNonCriticalKeyFlags causes the "Key Flags" signature subpacket
|
||||||
|
// to be non-critical in newly generated signatures.
|
||||||
|
// This may be needed for keys to be accepted by older clients who do not recognize
|
||||||
|
// the subpacket.
|
||||||
|
// For example, rpm 4.14.3-150400.59.3.1 in OpenSUSE Leap 15.4 does not recognize it.
|
||||||
|
InsecureGenerateNonCriticalKeyFlags bool
|
||||||
|
// InsecureGenerateNonCriticalSignatureCreationTime causes the "Signature Creation Time" signature subpacket
|
||||||
|
// to be non-critical in newly generated signatures.
|
||||||
|
// This may be needed for keys to be accepted by older clients who do not recognize
|
||||||
|
// the subpacket.
|
||||||
|
// For example, yum 3.4.3-168 in CentOS 7 and yum 3.4.3-158 in Amazon Linux 2 do not recognize it.
|
||||||
|
InsecureGenerateNonCriticalSignatureCreationTime bool
|
||||||
|
|
||||||
// MaxDecompressedMessageSize specifies the maximum number of bytes that can be
|
// MaxDecompressedMessageSize specifies the maximum number of bytes that can be
|
||||||
// read from a compressed packet. This serves as an upper limit to prevent
|
// read from a compressed packet. This serves as an upper limit to prevent
|
||||||
@ -420,6 +432,20 @@ func (c *Config) AllowAllKeyFlagsWhenMissing() bool {
|
|||||||
return c.InsecureAllowAllKeyFlagsWhenMissing
|
return c.InsecureAllowAllKeyFlagsWhenMissing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) GenerateNonCriticalKeyFlags() bool {
|
||||||
|
if c == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return c.InsecureGenerateNonCriticalKeyFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) GenerateNonCriticalSignatureCreationTime() bool {
|
||||||
|
if c == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return c.InsecureGenerateNonCriticalSignatureCreationTime
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) DecompressedMessageSizeLimit() *int64 {
|
func (c *Config) DecompressedMessageSizeLimit() *int64 {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
8
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
generated
vendored
8
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
generated
vendored
@ -933,7 +933,7 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
|
|||||||
}
|
}
|
||||||
sig.Notations = append(sig.Notations, ¬ation)
|
sig.Notations = append(sig.Notations, ¬ation)
|
||||||
}
|
}
|
||||||
sig.outSubpackets, err = sig.buildSubpackets(priv.PublicKey)
|
sig.outSubpackets, err = sig.buildSubpackets(priv.PublicKey, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1254,11 +1254,11 @@ type outputSubpacket struct {
|
|||||||
contents []byte
|
contents []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubpacket, err error) {
|
func (sig *Signature) buildSubpackets(issuer PublicKey, config *Config) (subpackets []outputSubpacket, err error) {
|
||||||
creationTime := make([]byte, 4)
|
creationTime := make([]byte, 4)
|
||||||
binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix()))
|
binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix()))
|
||||||
// Signature Creation Time
|
// Signature Creation Time
|
||||||
subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, true, creationTime})
|
subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, !config.GenerateNonCriticalSignatureCreationTime(), creationTime})
|
||||||
// Signature Expiration Time
|
// Signature Expiration Time
|
||||||
if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 {
|
if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 {
|
||||||
sigLifetime := make([]byte, 4)
|
sigLifetime := make([]byte, 4)
|
||||||
@ -1357,7 +1357,7 @@ func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubp
|
|||||||
if sig.FlagGroupKey {
|
if sig.FlagGroupKey {
|
||||||
flags |= KeyFlagGroupKey
|
flags |= KeyFlagGroupKey
|
||||||
}
|
}
|
||||||
subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, true, []byte{flags}})
|
subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, !config.GenerateNonCriticalKeyFlags(), []byte{flags}})
|
||||||
}
|
}
|
||||||
// Signer's User ID
|
// Signer's User ID
|
||||||
if sig.SignerUserId != nil {
|
if sig.SignerUserId != nil {
|
||||||
|
|||||||
3
vendor/github.com/charmbracelet/colorprofile/.golangci.yml
generated
vendored
3
vendor/github.com/charmbracelet/colorprofile/.golangci.yml
generated
vendored
@ -33,6 +33,9 @@ linters:
|
|||||||
generated: lax
|
generated: lax
|
||||||
presets:
|
presets:
|
||||||
- common-false-positives
|
- common-false-positives
|
||||||
|
settings:
|
||||||
|
exhaustive:
|
||||||
|
default-signifies-exhaustive: true
|
||||||
issues:
|
issues:
|
||||||
max-issues-per-linter: 0
|
max-issues-per-linter: 0
|
||||||
max-same-issues: 0
|
max-same-issues: 0
|
||||||
|
|||||||
47
vendor/github.com/charmbracelet/colorprofile/env.go
generated
vendored
47
vendor/github.com/charmbracelet/colorprofile/env.go
generated
vendored
@ -2,6 +2,7 @@ package colorprofile
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -83,8 +84,8 @@ func colorProfile(isatty bool, env environ) (p Profile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if envNoColor(env) && isatty {
|
if envNoColor(env) && isatty {
|
||||||
if p > Ascii {
|
if p > ASCII {
|
||||||
p = Ascii
|
p = ASCII
|
||||||
}
|
}
|
||||||
return //nolint:nakedret
|
return //nolint:nakedret
|
||||||
}
|
}
|
||||||
@ -153,29 +154,29 @@ func envColorProfile(env environ) (p Profile) {
|
|||||||
p = ANSI
|
p = ANSI
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.Split(term, "-")
|
switch {
|
||||||
switch parts[0] {
|
case strings.Contains(term, "alacritty"),
|
||||||
case "alacritty",
|
strings.Contains(term, "contour"),
|
||||||
"contour",
|
strings.Contains(term, "foot"),
|
||||||
"foot",
|
strings.Contains(term, "ghostty"),
|
||||||
"ghostty",
|
strings.Contains(term, "kitty"),
|
||||||
"kitty",
|
strings.Contains(term, "rio"),
|
||||||
"rio",
|
strings.Contains(term, "st"),
|
||||||
"st",
|
strings.Contains(term, "wezterm"):
|
||||||
"wezterm":
|
|
||||||
return TrueColor
|
return TrueColor
|
||||||
case "xterm":
|
case strings.HasPrefix(term, "tmux"), strings.HasPrefix(term, "screen"):
|
||||||
if len(parts) > 1 {
|
|
||||||
switch parts[1] {
|
|
||||||
case "ghostty", "kitty":
|
|
||||||
// These terminals can be defined as xterm-TERMNAME
|
|
||||||
return TrueColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "tmux", "screen":
|
|
||||||
if p < ANSI256 {
|
if p < ANSI256 {
|
||||||
p = ANSI256
|
p = ANSI256
|
||||||
}
|
}
|
||||||
|
case strings.HasPrefix(term, "xterm"):
|
||||||
|
if p < ANSI {
|
||||||
|
p = ANSI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(env["WT_SESSION"]) > 0 {
|
||||||
|
// Windows Terminal supports TrueColor
|
||||||
|
return TrueColor
|
||||||
}
|
}
|
||||||
|
|
||||||
if isCloudShell, _ := strconv.ParseBool(env.get("GOOGLE_CLOUD_SHELL")); isCloudShell {
|
if isCloudShell, _ := strconv.ParseBool(env.get("GOOGLE_CLOUD_SHELL")); isCloudShell {
|
||||||
@ -244,13 +245,13 @@ func tmux(env environ) (p Profile) {
|
|||||||
// Check if tmux has either Tc or RGB capabilities. Otherwise, return
|
// Check if tmux has either Tc or RGB capabilities. Otherwise, return
|
||||||
// ANSI256.
|
// ANSI256.
|
||||||
p = ANSI256
|
p = ANSI256
|
||||||
cmd := exec.Command("tmux", "info")
|
cmd := exec.CommandContext(context.Background(), "tmux", "info")
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, line := range bytes.Split(out, []byte("\n")) {
|
for line := range bytes.SplitSeq(out, []byte("\n")) {
|
||||||
if (bytes.Contains(line, []byte("Tc")) || bytes.Contains(line, []byte("RGB"))) &&
|
if (bytes.Contains(line, []byte("Tc")) || bytes.Contains(line, []byte("RGB"))) &&
|
||||||
bytes.Contains(line, []byte("true")) {
|
bytes.Contains(line, []byte("true")) {
|
||||||
return TrueColor
|
return TrueColor
|
||||||
|
|||||||
5
vendor/github.com/charmbracelet/colorprofile/env_windows.go
generated
vendored
5
vendor/github.com/charmbracelet/colorprofile/env_windows.go
generated
vendored
@ -14,11 +14,6 @@ func windowsColorProfile(env map[string]string) (Profile, bool) {
|
|||||||
return TrueColor, true
|
return TrueColor, true
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(env["WT_SESSION"]) > 0 {
|
|
||||||
// Windows Terminal supports TrueColor
|
|
||||||
return TrueColor, true
|
|
||||||
}
|
|
||||||
|
|
||||||
major, _, build := windows.RtlGetNtVersionNumbers()
|
major, _, build := windows.RtlGetNtVersionNumbers()
|
||||||
if build < 10586 || major < 10 {
|
if build < 10586 || major < 10 {
|
||||||
// No ANSI support before WindowsNT 10 build 10586
|
// No ANSI support before WindowsNT 10 build 10586
|
||||||
|
|||||||
26
vendor/github.com/charmbracelet/colorprofile/profile.go
generated
vendored
26
vendor/github.com/charmbracelet/colorprofile/profile.go
generated
vendored
@ -11,10 +11,12 @@ import (
|
|||||||
type Profile byte
|
type Profile byte
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// Unknown is a profile that represents the absence of a profile.
|
||||||
|
Unknown Profile = iota
|
||||||
// NoTTY is a profile with no terminal support.
|
// NoTTY is a profile with no terminal support.
|
||||||
NoTTY Profile = iota
|
NoTTY
|
||||||
// Ascii is a profile with no color support.
|
// ASCII is a profile with no color support.
|
||||||
Ascii //nolint:revive
|
ASCII
|
||||||
// ANSI is a profile with 16 colors (4-bit).
|
// ANSI is a profile with 16 colors (4-bit).
|
||||||
ANSI
|
ANSI
|
||||||
// ANSI256 is a profile with 256 colors (8-bit).
|
// ANSI256 is a profile with 256 colors (8-bit).
|
||||||
@ -23,6 +25,9 @@ const (
|
|||||||
TrueColor
|
TrueColor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Ascii is an alias for the [ASCII] profile for backwards compatibility.
|
||||||
|
const Ascii = ASCII //nolint:revive
|
||||||
|
|
||||||
// String returns the string representation of a Profile.
|
// String returns the string representation of a Profile.
|
||||||
func (p Profile) String() string {
|
func (p Profile) String() string {
|
||||||
switch p {
|
switch p {
|
||||||
@ -32,12 +37,13 @@ func (p Profile) String() string {
|
|||||||
return "ANSI256"
|
return "ANSI256"
|
||||||
case ANSI:
|
case ANSI:
|
||||||
return "ANSI"
|
return "ANSI"
|
||||||
case Ascii:
|
case ASCII:
|
||||||
return "Ascii"
|
return "Ascii"
|
||||||
case NoTTY:
|
case NoTTY:
|
||||||
return "NoTTY"
|
return "NoTTY"
|
||||||
|
default:
|
||||||
|
return "Unknown"
|
||||||
}
|
}
|
||||||
return "Unknown"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -50,7 +56,7 @@ var (
|
|||||||
|
|
||||||
// Convert transforms a given Color to a Color supported within the Profile.
|
// Convert transforms a given Color to a Color supported within the Profile.
|
||||||
func (p Profile) Convert(c color.Color) (cc color.Color) {
|
func (p Profile) Convert(c color.Color) (cc color.Color) {
|
||||||
if p <= Ascii {
|
if p <= ASCII {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if p == TrueColor {
|
if p == TrueColor {
|
||||||
@ -90,11 +96,13 @@ func (p Profile) Convert(c color.Color) (cc color.Color) {
|
|||||||
return c
|
return c
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if p == ANSI256 {
|
switch p {
|
||||||
|
case ANSI256:
|
||||||
return ansi.Convert256(c)
|
return ansi.Convert256(c)
|
||||||
} else if p == ANSI {
|
case ANSI:
|
||||||
return ansi.Convert16(c)
|
return ansi.Convert16(c)
|
||||||
|
default:
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
vendor/github.com/charmbracelet/colorprofile/writer.go
generated
vendored
20
vendor/github.com/charmbracelet/colorprofile/writer.go
generated
vendored
@ -36,13 +36,15 @@ type Writer struct {
|
|||||||
|
|
||||||
// Write writes the given text to the underlying writer.
|
// Write writes the given text to the underlying writer.
|
||||||
func (w *Writer) Write(p []byte) (int, error) {
|
func (w *Writer) Write(p []byte) (int, error) {
|
||||||
switch w.Profile {
|
switch {
|
||||||
case TrueColor:
|
case w.Profile == TrueColor:
|
||||||
return w.Forward.Write(p) //nolint:wrapcheck
|
return w.Forward.Write(p) //nolint:wrapcheck
|
||||||
case NoTTY:
|
case w.Profile <= NoTTY:
|
||||||
return io.WriteString(w.Forward, ansi.Strip(string(p))) //nolint:wrapcheck
|
_, err := io.WriteString(w.Forward, ansi.Strip(string(p)))
|
||||||
case Ascii, ANSI, ANSI256:
|
return len(p), err
|
||||||
return w.downsample(p)
|
case w.Profile == ASCII, w.Profile == ANSI, w.Profile == ANSI256:
|
||||||
|
_, err := w.downsample(p)
|
||||||
|
return len(p), err
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("invalid profile: %v", w.Profile)
|
return 0, fmt.Errorf("invalid profile: %v", w.Profile)
|
||||||
}
|
}
|
||||||
@ -112,7 +114,7 @@ func handleSgr(w *Writer, p *ansi.Parser, buf *bytes.Buffer) {
|
|||||||
if w.Profile < ANSI {
|
if w.Profile < ANSI {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
style = style.DefaultForegroundColor()
|
style = style.ForegroundColor(nil)
|
||||||
case 40, 41, 42, 43, 44, 45, 46, 47: // 8-bit background color
|
case 40, 41, 42, 43, 44, 45, 46, 47: // 8-bit background color
|
||||||
if w.Profile < ANSI {
|
if w.Profile < ANSI {
|
||||||
continue
|
continue
|
||||||
@ -132,7 +134,7 @@ func handleSgr(w *Writer, p *ansi.Parser, buf *bytes.Buffer) {
|
|||||||
if w.Profile < ANSI {
|
if w.Profile < ANSI {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
style = style.DefaultBackgroundColor()
|
style = style.BackgroundColor(nil)
|
||||||
case 58: // 16 or 24-bit underline color
|
case 58: // 16 or 24-bit underline color
|
||||||
var c color.Color
|
var c color.Color
|
||||||
if n := ansi.ReadStyleColor(params[i:], &c); n > 0 {
|
if n := ansi.ReadStyleColor(params[i:], &c); n > 0 {
|
||||||
@ -146,7 +148,7 @@ func handleSgr(w *Writer, p *ansi.Parser, buf *bytes.Buffer) {
|
|||||||
if w.Profile < ANSI {
|
if w.Profile < ANSI {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
style = style.DefaultUnderlineColor()
|
style = style.UnderlineColor(nil)
|
||||||
case 90, 91, 92, 93, 94, 95, 96, 97: // 8-bit bright foreground color
|
case 90, 91, 92, 93, 94, 95, 96, 97: // 8-bit bright foreground color
|
||||||
if w.Profile < ANSI {
|
if w.Profile < ANSI {
|
||||||
continue
|
continue
|
||||||
|
|||||||
8
vendor/github.com/charmbracelet/log/.golangci.yml
generated
vendored
8
vendor/github.com/charmbracelet/log/.golangci.yml
generated
vendored
@ -7,7 +7,6 @@ linters:
|
|||||||
- exhaustive
|
- exhaustive
|
||||||
- goconst
|
- goconst
|
||||||
- godot
|
- godot
|
||||||
- godox
|
|
||||||
- gomoddirectives
|
- gomoddirectives
|
||||||
- goprintffuncname
|
- goprintffuncname
|
||||||
- gosec
|
- gosec
|
||||||
@ -27,9 +26,16 @@ linters:
|
|||||||
- whitespace
|
- whitespace
|
||||||
- wrapcheck
|
- wrapcheck
|
||||||
exclusions:
|
exclusions:
|
||||||
|
rules:
|
||||||
|
- text: '(slog|log)\.\w+'
|
||||||
|
linters:
|
||||||
|
- noctx
|
||||||
generated: lax
|
generated: lax
|
||||||
presets:
|
presets:
|
||||||
- common-false-positives
|
- common-false-positives
|
||||||
|
settings:
|
||||||
|
exhaustive:
|
||||||
|
default-signifies-exhaustive: true
|
||||||
issues:
|
issues:
|
||||||
max-issues-per-linter: 0
|
max-issues-per-linter: 0
|
||||||
max-same-issues: 0
|
max-same-issues: 0
|
||||||
|
|||||||
2
vendor/github.com/charmbracelet/log/json.go
generated
vendored
2
vendor/github.com/charmbracelet/log/json.go
generated
vendored
@ -7,7 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (l *Logger) jsonFormatter(keyvals ...interface{}) {
|
func (l *Logger) jsonFormatter(keyvals ...any) {
|
||||||
jw := &jsonWriter{w: &l.b}
|
jw := &jsonWriter{w: &l.b}
|
||||||
jw.start()
|
jw.start()
|
||||||
|
|
||||||
|
|||||||
2
vendor/github.com/charmbracelet/log/logfmt.go
generated
vendored
2
vendor/github.com/charmbracelet/log/logfmt.go
generated
vendored
@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/go-logfmt/logfmt"
|
"github.com/go-logfmt/logfmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (l *Logger) logfmtFormatter(keyvals ...interface{}) {
|
func (l *Logger) logfmtFormatter(keyvals ...any) {
|
||||||
e := logfmt.NewEncoder(&l.b)
|
e := logfmt.NewEncoder(&l.b)
|
||||||
|
|
||||||
for i := 0; i < len(keyvals); i += 2 {
|
for i := 0; i < len(keyvals); i += 2 {
|
||||||
|
|||||||
38
vendor/github.com/charmbracelet/log/logger.go
generated
vendored
38
vendor/github.com/charmbracelet/log/logger.go
generated
vendored
@ -41,19 +41,19 @@ type Logger struct {
|
|||||||
reportCaller bool
|
reportCaller bool
|
||||||
reportTimestamp bool
|
reportTimestamp bool
|
||||||
|
|
||||||
fields []interface{}
|
fields []any
|
||||||
|
|
||||||
helpers *sync.Map
|
helpers *sync.Map
|
||||||
styles *Styles
|
styles *Styles
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logf logs a message with formatting.
|
// Logf logs a message with formatting.
|
||||||
func (l *Logger) Logf(level Level, format string, args ...interface{}) {
|
func (l *Logger) Logf(level Level, format string, args ...any) {
|
||||||
l.Log(level, fmt.Sprintf(format, args...))
|
l.Log(level, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log logs the given message with the given keyvals for the given level.
|
// Log logs the given message with the given keyvals for the given level.
|
||||||
func (l *Logger) Log(level Level, msg interface{}, keyvals ...interface{}) {
|
func (l *Logger) Log(level Level, msg any, keyvals ...any) {
|
||||||
if atomic.LoadUint32(&l.isDiscard) != 0 {
|
if atomic.LoadUint32(&l.isDiscard) != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -81,8 +81,8 @@ func (l *Logger) Log(level Level, msg interface{}, keyvals ...interface{}) {
|
|||||||
l.handle(level, l.timeFunc(time.Now()), []runtime.Frame{frame}, msg, keyvals...)
|
l.handle(level, l.timeFunc(time.Now()), []runtime.Frame{frame}, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) handle(level Level, ts time.Time, frames []runtime.Frame, msg interface{}, keyvals ...interface{}) {
|
func (l *Logger) handle(level Level, ts time.Time, frames []runtime.Frame, msg any, keyvals ...any) {
|
||||||
var kvs []interface{}
|
var kvs []any
|
||||||
if l.reportTimestamp && !ts.IsZero() {
|
if l.reportTimestamp && !ts.IsZero() {
|
||||||
kvs = append(kvs, TimestampKey, ts)
|
kvs = append(kvs, TimestampKey, ts)
|
||||||
}
|
}
|
||||||
@ -327,7 +327,7 @@ func (l *Logger) SetStyles(s *Styles) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// With returns a new logger with the given keyvals added.
|
// With returns a new logger with the given keyvals added.
|
||||||
func (l *Logger) With(keyvals ...interface{}) *Logger {
|
func (l *Logger) With(keyvals ...any) *Logger {
|
||||||
var st Styles
|
var st Styles
|
||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
sl := *l
|
sl := *l
|
||||||
@ -336,7 +336,7 @@ func (l *Logger) With(keyvals ...interface{}) *Logger {
|
|||||||
sl.b = bytes.Buffer{}
|
sl.b = bytes.Buffer{}
|
||||||
sl.mu = &sync.RWMutex{}
|
sl.mu = &sync.RWMutex{}
|
||||||
sl.helpers = &sync.Map{}
|
sl.helpers = &sync.Map{}
|
||||||
sl.fields = append(make([]interface{}, 0, len(l.fields)+len(keyvals)), l.fields...)
|
sl.fields = append(make([]any, 0, len(l.fields)+len(keyvals)), l.fields...)
|
||||||
sl.fields = append(sl.fields, keyvals...)
|
sl.fields = append(sl.fields, keyvals...)
|
||||||
sl.styles = &st
|
sl.styles = &st
|
||||||
return &sl
|
return &sl
|
||||||
@ -350,63 +350,63 @@ func (l *Logger) WithPrefix(prefix string) *Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Debug prints a debug message.
|
// Debug prints a debug message.
|
||||||
func (l *Logger) Debug(msg interface{}, keyvals ...interface{}) {
|
func (l *Logger) Debug(msg any, keyvals ...any) {
|
||||||
l.Log(DebugLevel, msg, keyvals...)
|
l.Log(DebugLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info prints an info message.
|
// Info prints an info message.
|
||||||
func (l *Logger) Info(msg interface{}, keyvals ...interface{}) {
|
func (l *Logger) Info(msg any, keyvals ...any) {
|
||||||
l.Log(InfoLevel, msg, keyvals...)
|
l.Log(InfoLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn prints a warning message.
|
// Warn prints a warning message.
|
||||||
func (l *Logger) Warn(msg interface{}, keyvals ...interface{}) {
|
func (l *Logger) Warn(msg any, keyvals ...any) {
|
||||||
l.Log(WarnLevel, msg, keyvals...)
|
l.Log(WarnLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error prints an error message.
|
// Error prints an error message.
|
||||||
func (l *Logger) Error(msg interface{}, keyvals ...interface{}) {
|
func (l *Logger) Error(msg any, keyvals ...any) {
|
||||||
l.Log(ErrorLevel, msg, keyvals...)
|
l.Log(ErrorLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal prints a fatal message and exits.
|
// Fatal prints a fatal message and exits.
|
||||||
func (l *Logger) Fatal(msg interface{}, keyvals ...interface{}) {
|
func (l *Logger) Fatal(msg any, keyvals ...any) {
|
||||||
l.Log(FatalLevel, msg, keyvals...)
|
l.Log(FatalLevel, msg, keyvals...)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print prints a message with no level.
|
// Print prints a message with no level.
|
||||||
func (l *Logger) Print(msg interface{}, keyvals ...interface{}) {
|
func (l *Logger) Print(msg any, keyvals ...any) {
|
||||||
l.Log(noLevel, msg, keyvals...)
|
l.Log(noLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugf prints a debug message with formatting.
|
// Debugf prints a debug message with formatting.
|
||||||
func (l *Logger) Debugf(format string, args ...interface{}) {
|
func (l *Logger) Debugf(format string, args ...any) {
|
||||||
l.Log(DebugLevel, fmt.Sprintf(format, args...))
|
l.Log(DebugLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infof prints an info message with formatting.
|
// Infof prints an info message with formatting.
|
||||||
func (l *Logger) Infof(format string, args ...interface{}) {
|
func (l *Logger) Infof(format string, args ...any) {
|
||||||
l.Log(InfoLevel, fmt.Sprintf(format, args...))
|
l.Log(InfoLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warnf prints a warning message with formatting.
|
// Warnf prints a warning message with formatting.
|
||||||
func (l *Logger) Warnf(format string, args ...interface{}) {
|
func (l *Logger) Warnf(format string, args ...any) {
|
||||||
l.Log(WarnLevel, fmt.Sprintf(format, args...))
|
l.Log(WarnLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorf prints an error message with formatting.
|
// Errorf prints an error message with formatting.
|
||||||
func (l *Logger) Errorf(format string, args ...interface{}) {
|
func (l *Logger) Errorf(format string, args ...any) {
|
||||||
l.Log(ErrorLevel, fmt.Sprintf(format, args...))
|
l.Log(ErrorLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf prints a fatal message with formatting and exits.
|
// Fatalf prints a fatal message with formatting and exits.
|
||||||
func (l *Logger) Fatalf(format string, args ...interface{}) {
|
func (l *Logger) Fatalf(format string, args ...any) {
|
||||||
l.Log(FatalLevel, fmt.Sprintf(format, args...))
|
l.Log(FatalLevel, fmt.Sprintf(format, args...))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Printf prints a message with no level and formatting.
|
// Printf prints a message with no level and formatting.
|
||||||
func (l *Logger) Printf(format string, args ...interface{}) {
|
func (l *Logger) Printf(format string, args ...any) {
|
||||||
l.Log(noLevel, fmt.Sprintf(format, args...))
|
l.Log(noLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|||||||
4
vendor/github.com/charmbracelet/log/logger_121.go
generated
vendored
4
vendor/github.com/charmbracelet/log/logger_121.go
generated
vendored
@ -36,7 +36,7 @@ func (l *Logger) Handle(ctx context.Context, record slog.Record) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := make([]interface{}, 0, record.NumAttrs()*2)
|
fields := make([]any, 0, record.NumAttrs()*2)
|
||||||
record.Attrs(func(a slog.Attr) bool {
|
record.Attrs(func(a slog.Attr) bool {
|
||||||
fields = append(fields, a.Key, a.Value)
|
fields = append(fields, a.Key, a.Value)
|
||||||
return true
|
return true
|
||||||
@ -52,7 +52,7 @@ func (l *Logger) Handle(ctx context.Context, record slog.Record) error {
|
|||||||
//
|
//
|
||||||
// Implements slog.Handler.
|
// Implements slog.Handler.
|
||||||
func (l *Logger) WithAttrs(attrs []slog.Attr) slog.Handler {
|
func (l *Logger) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||||
fields := make([]interface{}, 0, len(attrs)*2)
|
fields := make([]any, 0, len(attrs)*2)
|
||||||
for _, attr := range attrs {
|
for _, attr := range attrs {
|
||||||
fields = append(fields, attr.Key, attr.Value)
|
fields = append(fields, attr.Key, attr.Value)
|
||||||
}
|
}
|
||||||
|
|||||||
4
vendor/github.com/charmbracelet/log/logger_no121.go
generated
vendored
4
vendor/github.com/charmbracelet/log/logger_no121.go
generated
vendored
@ -33,7 +33,7 @@ func (l *Logger) Enabled(_ context.Context, level slog.Level) bool {
|
|||||||
//
|
//
|
||||||
// Implements slog.Handler.
|
// Implements slog.Handler.
|
||||||
func (l *Logger) Handle(_ context.Context, record slog.Record) error {
|
func (l *Logger) Handle(_ context.Context, record slog.Record) error {
|
||||||
fields := make([]interface{}, 0, record.NumAttrs()*2)
|
fields := make([]any, 0, record.NumAttrs()*2)
|
||||||
record.Attrs(func(a slog.Attr) bool {
|
record.Attrs(func(a slog.Attr) bool {
|
||||||
fields = append(fields, a.Key, a.Value)
|
fields = append(fields, a.Key, a.Value)
|
||||||
return true
|
return true
|
||||||
@ -49,7 +49,7 @@ func (l *Logger) Handle(_ context.Context, record slog.Record) error {
|
|||||||
//
|
//
|
||||||
// Implements slog.Handler.
|
// Implements slog.Handler.
|
||||||
func (l *Logger) WithAttrs(attrs []slog.Attr) slog.Handler {
|
func (l *Logger) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||||
fields := make([]interface{}, 0, len(attrs)*2)
|
fields := make([]any, 0, len(attrs)*2)
|
||||||
for _, attr := range attrs {
|
for _, attr := range attrs {
|
||||||
fields = append(fields, attr.Key, attr.Value)
|
fields = append(fields, attr.Key, attr.Value)
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/charmbracelet/log/options.go
generated
vendored
2
vendor/github.com/charmbracelet/log/options.go
generated
vendored
@ -55,7 +55,7 @@ type Options struct {
|
|||||||
// CallerOffset is the caller format for the logger. The default is 0.
|
// CallerOffset is the caller format for the logger. The default is 0.
|
||||||
CallerOffset int
|
CallerOffset int
|
||||||
// Fields is the fields for the logger. The default is no fields.
|
// Fields is the fields for the logger. The default is no fields.
|
||||||
Fields []interface{}
|
Fields []any
|
||||||
// Formatter is the formatter for the logger. The default is TextFormatter.
|
// Formatter is the formatter for the logger. The default is TextFormatter.
|
||||||
Formatter Formatter
|
Formatter Formatter
|
||||||
}
|
}
|
||||||
|
|||||||
30
vendor/github.com/charmbracelet/log/pkg.go
generated
vendored
30
vendor/github.com/charmbracelet/log/pkg.go
generated
vendored
@ -155,7 +155,7 @@ func GetPrefix() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// With returns a new logger with the given keyvals.
|
// With returns a new logger with the given keyvals.
|
||||||
func With(keyvals ...interface{}) *Logger {
|
func With(keyvals ...any) *Logger {
|
||||||
return Default().With(keyvals...)
|
return Default().With(keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,74 +172,74 @@ func Helper() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log logs a message with the given level.
|
// Log logs a message with the given level.
|
||||||
func Log(level Level, msg interface{}, keyvals ...interface{}) {
|
func Log(level Level, msg any, keyvals ...any) {
|
||||||
Default().Log(level, msg, keyvals...)
|
Default().Log(level, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug logs a debug message.
|
// Debug logs a debug message.
|
||||||
func Debug(msg interface{}, keyvals ...interface{}) {
|
func Debug(msg any, keyvals ...any) {
|
||||||
Default().Log(DebugLevel, msg, keyvals...)
|
Default().Log(DebugLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info logs an info message.
|
// Info logs an info message.
|
||||||
func Info(msg interface{}, keyvals ...interface{}) {
|
func Info(msg any, keyvals ...any) {
|
||||||
Default().Log(InfoLevel, msg, keyvals...)
|
Default().Log(InfoLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn logs a warning message.
|
// Warn logs a warning message.
|
||||||
func Warn(msg interface{}, keyvals ...interface{}) {
|
func Warn(msg any, keyvals ...any) {
|
||||||
Default().Log(WarnLevel, msg, keyvals...)
|
Default().Log(WarnLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error logs an error message.
|
// Error logs an error message.
|
||||||
func Error(msg interface{}, keyvals ...interface{}) {
|
func Error(msg any, keyvals ...any) {
|
||||||
Default().Log(ErrorLevel, msg, keyvals...)
|
Default().Log(ErrorLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal logs a fatal message and exit.
|
// Fatal logs a fatal message and exit.
|
||||||
func Fatal(msg interface{}, keyvals ...interface{}) {
|
func Fatal(msg any, keyvals ...any) {
|
||||||
Default().Log(FatalLevel, msg, keyvals...)
|
Default().Log(FatalLevel, msg, keyvals...)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print logs a message with no level.
|
// Print logs a message with no level.
|
||||||
func Print(msg interface{}, keyvals ...interface{}) {
|
func Print(msg any, keyvals ...any) {
|
||||||
Default().Log(noLevel, msg, keyvals...)
|
Default().Log(noLevel, msg, keyvals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logf logs a message with formatting and level.
|
// Logf logs a message with formatting and level.
|
||||||
func Logf(level Level, format string, args ...interface{}) {
|
func Logf(level Level, format string, args ...any) {
|
||||||
Default().Logf(level, format, args...)
|
Default().Logf(level, format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugf logs a debug message with formatting.
|
// Debugf logs a debug message with formatting.
|
||||||
func Debugf(format string, args ...interface{}) {
|
func Debugf(format string, args ...any) {
|
||||||
Default().Log(DebugLevel, fmt.Sprintf(format, args...))
|
Default().Log(DebugLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infof logs an info message with formatting.
|
// Infof logs an info message with formatting.
|
||||||
func Infof(format string, args ...interface{}) {
|
func Infof(format string, args ...any) {
|
||||||
Default().Log(InfoLevel, fmt.Sprintf(format, args...))
|
Default().Log(InfoLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warnf logs a warning message with formatting.
|
// Warnf logs a warning message with formatting.
|
||||||
func Warnf(format string, args ...interface{}) {
|
func Warnf(format string, args ...any) {
|
||||||
Default().Log(WarnLevel, fmt.Sprintf(format, args...))
|
Default().Log(WarnLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorf logs an error message with formatting.
|
// Errorf logs an error message with formatting.
|
||||||
func Errorf(format string, args ...interface{}) {
|
func Errorf(format string, args ...any) {
|
||||||
Default().Log(ErrorLevel, fmt.Sprintf(format, args...))
|
Default().Log(ErrorLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf logs a fatal message with formatting and exit.
|
// Fatalf logs a fatal message with formatting and exit.
|
||||||
func Fatalf(format string, args ...interface{}) {
|
func Fatalf(format string, args ...any) {
|
||||||
Default().Log(FatalLevel, fmt.Sprintf(format, args...))
|
Default().Log(FatalLevel, fmt.Sprintf(format, args...))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Printf logs a message with formatting and no level.
|
// Printf logs a message with formatting and no level.
|
||||||
func Printf(format string, args ...interface{}) {
|
func Printf(format string, args ...any) {
|
||||||
Default().Log(noLevel, fmt.Sprintf(format, args...))
|
Default().Log(noLevel, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
vendor/github.com/charmbracelet/log/text.go
generated
vendored
4
vendor/github.com/charmbracelet/log/text.go
generated
vendored
@ -62,7 +62,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var bufPool = sync.Pool{
|
var bufPool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
return new(strings.Builder)
|
return new(strings.Builder)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ func writeSpace(w io.Writer, first bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) textFormatter(keyvals ...interface{}) {
|
func (l *Logger) textFormatter(keyvals ...any) {
|
||||||
st := l.styles
|
st := l.styles
|
||||||
lenKeyvals := len(keyvals)
|
lenKeyvals := len(keyvals)
|
||||||
|
|
||||||
|
|||||||
6
vendor/github.com/charmbracelet/x/ansi/cursor.go
generated
vendored
6
vendor/github.com/charmbracelet/x/ansi/cursor.go
generated
vendored
@ -261,7 +261,7 @@ func CHA(col int) string {
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/CUP.html
|
// See: https://vt100.net/docs/vt510-rm/CUP.html
|
||||||
func CursorPosition(col, row int) string {
|
func CursorPosition(col, row int) string {
|
||||||
if row <= 0 && col <= 0 {
|
if row <= 1 && col <= 1 {
|
||||||
return CursorHomePosition
|
return CursorHomePosition
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +281,9 @@ func CUP(col, row int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CursorHomePosition is a sequence for moving the cursor to the upper left
|
// CursorHomePosition is a sequence for moving the cursor to the upper left
|
||||||
// corner of the scrolling region. This is equivalent to `CursorPosition(1, 1)`.
|
// corner of the scrolling region.
|
||||||
|
//
|
||||||
|
// This is equivalent to [CursorPosition](1, 1).
|
||||||
const CursorHomePosition = "\x1b[H"
|
const CursorHomePosition = "\x1b[H"
|
||||||
|
|
||||||
// SetCursorPosition (CUP) returns a sequence for setting the cursor to the
|
// SetCursorPosition (CUP) returns a sequence for setting the cursor to the
|
||||||
|
|||||||
24
vendor/github.com/charmbracelet/x/ansi/method.go
generated
vendored
24
vendor/github.com/charmbracelet/x/ansi/method.go
generated
vendored
@ -1,5 +1,29 @@
|
|||||||
package ansi
|
package ansi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/clipperhouse/displaywidth"
|
||||||
|
"github.com/mattn/go-runewidth"
|
||||||
|
)
|
||||||
|
|
||||||
|
var wcOptions = &runewidth.Condition{
|
||||||
|
EastAsianWidth: false,
|
||||||
|
StrictEmojiNeutral: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
var dwOptions = &displaywidth.Options{
|
||||||
|
EastAsianWidth: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if ea, err := strconv.ParseBool(os.Getenv("RUNEWIDTH_EASTASIAN")); err == nil && ea {
|
||||||
|
wcOptions.EastAsianWidth = true
|
||||||
|
dwOptions.EastAsianWidth = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Method is a type that represents the how the renderer should calculate the
|
// Method is a type that represents the how the renderer should calculate the
|
||||||
// display width of cells.
|
// display width of cells.
|
||||||
type Method uint8
|
type Method uint8
|
||||||
|
|||||||
465
vendor/github.com/charmbracelet/x/ansi/mode.go
generated
vendored
465
vendor/github.com/charmbracelet/x/ansi/mode.go
generated
vendored
@ -108,7 +108,7 @@ func DECRST(modes ...Mode) string {
|
|||||||
|
|
||||||
func setMode(reset bool, modes ...Mode) (s string) {
|
func setMode(reset bool, modes ...Mode) (s string) {
|
||||||
if len(modes) == 0 {
|
if len(modes) == 0 {
|
||||||
return //nolint:nakedret
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := "h"
|
cmd := "h"
|
||||||
@ -142,7 +142,7 @@ func setMode(reset bool, modes ...Mode) (s string) {
|
|||||||
if len(dec) > 0 {
|
if len(dec) > 0 {
|
||||||
s += seq + "?" + strings.Join(dec, ";") + cmd
|
s += seq + "?" + strings.Join(dec, ";") + cmd
|
||||||
}
|
}
|
||||||
return //nolint:nakedret
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestMode (DECRQM) returns a sequence to request a mode from the terminal.
|
// RequestMode (DECRQM) returns a sequence to request a mode from the terminal.
|
||||||
@ -228,12 +228,12 @@ func (m DECMode) Mode() int {
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/KAM.html
|
// See: https://vt100.net/docs/vt510-rm/KAM.html
|
||||||
const (
|
const (
|
||||||
KeyboardActionMode = ANSIMode(2)
|
ModeKeyboardAction = ANSIMode(2)
|
||||||
KAM = KeyboardActionMode
|
KAM = ModeKeyboardAction
|
||||||
|
|
||||||
SetKeyboardActionMode = "\x1b[2h"
|
SetModeKeyboardAction = "\x1b[2h"
|
||||||
ResetKeyboardActionMode = "\x1b[2l"
|
ResetModeKeyboardAction = "\x1b[2l"
|
||||||
RequestKeyboardActionMode = "\x1b[2$p"
|
RequestModeKeyboardAction = "\x1b[2$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Insert/Replace Mode (IRM) is a mode that determines whether characters are
|
// Insert/Replace Mode (IRM) is a mode that determines whether characters are
|
||||||
@ -245,12 +245,12 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/IRM.html
|
// See: https://vt100.net/docs/vt510-rm/IRM.html
|
||||||
const (
|
const (
|
||||||
InsertReplaceMode = ANSIMode(4)
|
ModeInsertReplace = ANSIMode(4)
|
||||||
IRM = InsertReplaceMode
|
IRM = ModeInsertReplace
|
||||||
|
|
||||||
SetInsertReplaceMode = "\x1b[4h"
|
SetModeInsertReplace = "\x1b[4h"
|
||||||
ResetInsertReplaceMode = "\x1b[4l"
|
ResetModeInsertReplace = "\x1b[4l"
|
||||||
RequestInsertReplaceMode = "\x1b[4$p"
|
RequestModeInsertReplace = "\x1b[4$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BiDirectional Support Mode (BDSM) is a mode that determines whether the
|
// BiDirectional Support Mode (BDSM) is a mode that determines whether the
|
||||||
@ -260,12 +260,12 @@ const (
|
|||||||
//
|
//
|
||||||
// See ECMA-48 7.2.1.
|
// See ECMA-48 7.2.1.
|
||||||
const (
|
const (
|
||||||
BiDirectionalSupportMode = ANSIMode(8)
|
ModeBiDirectionalSupport = ANSIMode(8)
|
||||||
BDSM = BiDirectionalSupportMode
|
BDSM = ModeBiDirectionalSupport
|
||||||
|
|
||||||
SetBiDirectionalSupportMode = "\x1b[8h"
|
SetModeBiDirectionalSupport = "\x1b[8h"
|
||||||
ResetBiDirectionalSupportMode = "\x1b[8l"
|
ResetModeBiDirectionalSupport = "\x1b[8l"
|
||||||
RequestBiDirectionalSupportMode = "\x1b[8$p"
|
RequestModeBiDirectionalSupport = "\x1b[8$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Send Receive Mode (SRM) or Local Echo Mode is a mode that determines whether
|
// Send Receive Mode (SRM) or Local Echo Mode is a mode that determines whether
|
||||||
@ -274,17 +274,17 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/SRM.html
|
// See: https://vt100.net/docs/vt510-rm/SRM.html
|
||||||
const (
|
const (
|
||||||
SendReceiveMode = ANSIMode(12)
|
ModeSendReceive = ANSIMode(12)
|
||||||
LocalEchoMode = SendReceiveMode
|
ModeLocalEcho = ModeSendReceive
|
||||||
SRM = SendReceiveMode
|
SRM = ModeSendReceive
|
||||||
|
|
||||||
SetSendReceiveMode = "\x1b[12h"
|
SetModeSendReceive = "\x1b[12h"
|
||||||
ResetSendReceiveMode = "\x1b[12l"
|
ResetModeSendReceive = "\x1b[12l"
|
||||||
RequestSendReceiveMode = "\x1b[12$p"
|
RequestModeSendReceive = "\x1b[12$p"
|
||||||
|
|
||||||
SetLocalEchoMode = "\x1b[12h"
|
SetModeLocalEcho = "\x1b[12h"
|
||||||
ResetLocalEchoMode = "\x1b[12l"
|
ResetModeLocalEcho = "\x1b[12l"
|
||||||
RequestLocalEchoMode = "\x1b[12$p"
|
RequestModeLocalEcho = "\x1b[12$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Line Feed/New Line Mode (LNM) is a mode that determines whether the terminal
|
// Line Feed/New Line Mode (LNM) is a mode that determines whether the terminal
|
||||||
@ -299,12 +299,12 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/LNM.html
|
// See: https://vt100.net/docs/vt510-rm/LNM.html
|
||||||
const (
|
const (
|
||||||
LineFeedNewLineMode = ANSIMode(20)
|
ModeLineFeedNewLine = ANSIMode(20)
|
||||||
LNM = LineFeedNewLineMode
|
LNM = ModeLineFeedNewLine
|
||||||
|
|
||||||
SetLineFeedNewLineMode = "\x1b[20h"
|
SetModeLineFeedNewLine = "\x1b[20h"
|
||||||
ResetLineFeedNewLineMode = "\x1b[20l"
|
ResetModeLineFeedNewLine = "\x1b[20l"
|
||||||
RequestLineFeedNewLineMode = "\x1b[20$p"
|
RequestModeLineFeedNewLine = "\x1b[20$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cursor Keys Mode (DECCKM) is a mode that determines whether the cursor keys
|
// Cursor Keys Mode (DECCKM) is a mode that determines whether the cursor keys
|
||||||
@ -312,18 +312,12 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECCKM.html
|
// See: https://vt100.net/docs/vt510-rm/DECCKM.html
|
||||||
const (
|
const (
|
||||||
CursorKeysMode = DECMode(1)
|
ModeCursorKeys = DECMode(1)
|
||||||
DECCKM = CursorKeysMode
|
DECCKM = ModeCursorKeys
|
||||||
|
|
||||||
SetCursorKeysMode = "\x1b[?1h"
|
SetModeCursorKeys = "\x1b[?1h"
|
||||||
ResetCursorKeysMode = "\x1b[?1l"
|
ResetModeCursorKeys = "\x1b[?1l"
|
||||||
RequestCursorKeysMode = "\x1b[?1$p"
|
RequestModeCursorKeys = "\x1b[?1$p"
|
||||||
)
|
|
||||||
|
|
||||||
// Deprecated: use [SetCursorKeysMode] and [ResetCursorKeysMode] instead.
|
|
||||||
const (
|
|
||||||
EnableCursorKeys = "\x1b[?1h" //nolint:revive // grouped constants
|
|
||||||
DisableCursorKeys = "\x1b[?1l"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Origin Mode (DECOM) is a mode that determines whether the cursor moves to the
|
// Origin Mode (DECOM) is a mode that determines whether the cursor moves to the
|
||||||
@ -331,12 +325,12 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECOM.html
|
// See: https://vt100.net/docs/vt510-rm/DECOM.html
|
||||||
const (
|
const (
|
||||||
OriginMode = DECMode(6)
|
ModeOrigin = DECMode(6)
|
||||||
DECOM = OriginMode
|
DECOM = ModeOrigin
|
||||||
|
|
||||||
SetOriginMode = "\x1b[?6h"
|
SetModeOrigin = "\x1b[?6h"
|
||||||
ResetOriginMode = "\x1b[?6l"
|
ResetModeOrigin = "\x1b[?6l"
|
||||||
RequestOriginMode = "\x1b[?6$p"
|
RequestModeOrigin = "\x1b[?6$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Auto Wrap Mode (DECAWM) is a mode that determines whether the cursor wraps
|
// Auto Wrap Mode (DECAWM) is a mode that determines whether the cursor wraps
|
||||||
@ -344,12 +338,12 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECAWM.html
|
// See: https://vt100.net/docs/vt510-rm/DECAWM.html
|
||||||
const (
|
const (
|
||||||
AutoWrapMode = DECMode(7)
|
ModeAutoWrap = DECMode(7)
|
||||||
DECAWM = AutoWrapMode
|
DECAWM = ModeAutoWrap
|
||||||
|
|
||||||
SetAutoWrapMode = "\x1b[?7h"
|
SetModeAutoWrap = "\x1b[?7h"
|
||||||
ResetAutoWrapMode = "\x1b[?7l"
|
ResetModeAutoWrap = "\x1b[?7l"
|
||||||
RequestAutoWrapMode = "\x1b[?7$p"
|
RequestModeAutoWrap = "\x1b[?7$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// X10 Mouse Mode is a mode that determines whether the mouse reports on button
|
// X10 Mouse Mode is a mode that determines whether the mouse reports on button
|
||||||
@ -364,39 +358,29 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
const (
|
const (
|
||||||
X10MouseMode = DECMode(9)
|
ModeMouseX10 = DECMode(9)
|
||||||
|
|
||||||
SetX10MouseMode = "\x1b[?9h"
|
SetModeMouseX10 = "\x1b[?9h"
|
||||||
ResetX10MouseMode = "\x1b[?9l"
|
ResetModeMouseX10 = "\x1b[?9l"
|
||||||
RequestX10MouseMode = "\x1b[?9$p"
|
RequestModeMouseX10 = "\x1b[?9$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor.
|
// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor.
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECTCEM.html
|
// See: https://vt100.net/docs/vt510-rm/DECTCEM.html
|
||||||
const (
|
const (
|
||||||
TextCursorEnableMode = DECMode(25)
|
ModeTextCursorEnable = DECMode(25)
|
||||||
DECTCEM = TextCursorEnableMode
|
DECTCEM = ModeTextCursorEnable
|
||||||
|
|
||||||
SetTextCursorEnableMode = "\x1b[?25h"
|
SetModeTextCursorEnable = "\x1b[?25h"
|
||||||
ResetTextCursorEnableMode = "\x1b[?25l"
|
ResetModeTextCursorEnable = "\x1b[?25l"
|
||||||
RequestTextCursorEnableMode = "\x1b[?25$p"
|
RequestModeTextCursorEnable = "\x1b[?25$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// These are aliases for [SetTextCursorEnableMode] and [ResetTextCursorEnableMode].
|
// These are aliases for [SetModeTextCursorEnable] and [ResetModeTextCursorEnable].
|
||||||
const (
|
const (
|
||||||
ShowCursor = SetTextCursorEnableMode
|
ShowCursor = SetModeTextCursorEnable
|
||||||
HideCursor = ResetTextCursorEnableMode
|
HideCursor = ResetModeTextCursorEnable
|
||||||
)
|
|
||||||
|
|
||||||
// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor.
|
|
||||||
//
|
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECTCEM.html
|
|
||||||
//
|
|
||||||
// Deprecated: use [SetTextCursorEnableMode] and [ResetTextCursorEnableMode] instead.
|
|
||||||
const (
|
|
||||||
CursorEnableMode = DECMode(25)
|
|
||||||
RequestCursorVisibility = "\x1b[?25$p"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Numeric Keypad Mode (DECNKM) is a mode that determines whether the keypad
|
// Numeric Keypad Mode (DECNKM) is a mode that determines whether the keypad
|
||||||
@ -406,12 +390,12 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECNKM.html
|
// See: https://vt100.net/docs/vt510-rm/DECNKM.html
|
||||||
const (
|
const (
|
||||||
NumericKeypadMode = DECMode(66)
|
ModeNumericKeypad = DECMode(66)
|
||||||
DECNKM = NumericKeypadMode
|
DECNKM = ModeNumericKeypad
|
||||||
|
|
||||||
SetNumericKeypadMode = "\x1b[?66h"
|
SetModeNumericKeypad = "\x1b[?66h"
|
||||||
ResetNumericKeypadMode = "\x1b[?66l"
|
ResetModeNumericKeypad = "\x1b[?66l"
|
||||||
RequestNumericKeypadMode = "\x1b[?66$p"
|
RequestModeNumericKeypad = "\x1b[?66$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Backarrow Key Mode (DECBKM) is a mode that determines whether the backspace
|
// Backarrow Key Mode (DECBKM) is a mode that determines whether the backspace
|
||||||
@ -419,12 +403,12 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECBKM.html
|
// See: https://vt100.net/docs/vt510-rm/DECBKM.html
|
||||||
const (
|
const (
|
||||||
BackarrowKeyMode = DECMode(67)
|
ModeBackarrowKey = DECMode(67)
|
||||||
DECBKM = BackarrowKeyMode
|
DECBKM = ModeBackarrowKey
|
||||||
|
|
||||||
SetBackarrowKeyMode = "\x1b[?67h"
|
SetModeBackarrowKey = "\x1b[?67h"
|
||||||
ResetBackarrowKeyMode = "\x1b[?67l"
|
ResetModeBackarrowKey = "\x1b[?67l"
|
||||||
RequestBackarrowKeyMode = "\x1b[?67$p"
|
RequestModeBackarrowKey = "\x1b[?67$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Left Right Margin Mode (DECLRMM) is a mode that determines whether the left
|
// Left Right Margin Mode (DECLRMM) is a mode that determines whether the left
|
||||||
@ -432,47 +416,33 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECLRMM.html
|
// See: https://vt100.net/docs/vt510-rm/DECLRMM.html
|
||||||
const (
|
const (
|
||||||
LeftRightMarginMode = DECMode(69)
|
ModeLeftRightMargin = DECMode(69)
|
||||||
DECLRMM = LeftRightMarginMode
|
DECLRMM = ModeLeftRightMargin
|
||||||
|
|
||||||
SetLeftRightMarginMode = "\x1b[?69h"
|
SetModeLeftRightMargin = "\x1b[?69h"
|
||||||
ResetLeftRightMarginMode = "\x1b[?69l"
|
ResetModeLeftRightMargin = "\x1b[?69l"
|
||||||
RequestLeftRightMarginMode = "\x1b[?69$p"
|
RequestModeLeftRightMargin = "\x1b[?69$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Normal Mouse Mode is a mode that determines whether the mouse reports on
|
// Normal Mouse Mode is a mode that determines whether the mouse reports on
|
||||||
// button presses and releases. It will also report modifier keys, wheel
|
// button presses and releases. It will also report modifier keys, wheel
|
||||||
// events, and extra buttons.
|
// events, and extra buttons.
|
||||||
//
|
//
|
||||||
// It uses the same encoding as [X10MouseMode] with a few differences:
|
// It uses the same encoding as [ModeMouseX10] with a few differences:
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
const (
|
const (
|
||||||
NormalMouseMode = DECMode(1000)
|
ModeMouseNormal = DECMode(1000)
|
||||||
|
|
||||||
SetNormalMouseMode = "\x1b[?1000h"
|
SetModeMouseNormal = "\x1b[?1000h"
|
||||||
ResetNormalMouseMode = "\x1b[?1000l"
|
ResetModeMouseNormal = "\x1b[?1000l"
|
||||||
RequestNormalMouseMode = "\x1b[?1000$p"
|
RequestModeMouseNormal = "\x1b[?1000$p"
|
||||||
)
|
|
||||||
|
|
||||||
// VT Mouse Tracking is a mode that determines whether the mouse reports on
|
|
||||||
// button press and release.
|
|
||||||
//
|
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
|
||||||
//
|
|
||||||
// Deprecated: use [NormalMouseMode] instead.
|
|
||||||
const (
|
|
||||||
MouseMode = DECMode(1000)
|
|
||||||
|
|
||||||
EnableMouse = "\x1b[?1000h"
|
|
||||||
DisableMouse = "\x1b[?1000l"
|
|
||||||
RequestMouse = "\x1b[?1000$p"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Highlight Mouse Tracking is a mode that determines whether the mouse reports
|
// Highlight Mouse Tracking is a mode that determines whether the mouse reports
|
||||||
// on button presses, releases, and highlighted cells.
|
// on button presses, releases, and highlighted cells.
|
||||||
//
|
//
|
||||||
// It uses the same encoding as [NormalMouseMode] with a few differences:
|
// It uses the same encoding as [ModeMouseNormal] with a few differences:
|
||||||
//
|
//
|
||||||
// On highlight events, the terminal responds with the following encoding:
|
// On highlight events, the terminal responds with the following encoding:
|
||||||
//
|
//
|
||||||
@ -481,11 +451,11 @@ const (
|
|||||||
//
|
//
|
||||||
// Where the parameters are startx, starty, endx, endy, mousex, and mousey.
|
// Where the parameters are startx, starty, endx, endy, mousex, and mousey.
|
||||||
const (
|
const (
|
||||||
HighlightMouseMode = DECMode(1001)
|
ModeMouseHighlight = DECMode(1001)
|
||||||
|
|
||||||
SetHighlightMouseMode = "\x1b[?1001h"
|
SetModeMouseHighlight = "\x1b[?1001h"
|
||||||
ResetHighlightMouseMode = "\x1b[?1001l"
|
ResetModeMouseHighlight = "\x1b[?1001l"
|
||||||
RequestHighlightMouseMode = "\x1b[?1001$p"
|
RequestModeMouseHighlight = "\x1b[?1001$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VT Hilite Mouse Tracking is a mode that determines whether the mouse reports on
|
// VT Hilite Mouse Tracking is a mode that determines whether the mouse reports on
|
||||||
@ -493,65 +463,29 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
//
|
//
|
||||||
// Deprecated: use [HighlightMouseMode] instead.
|
|
||||||
const (
|
|
||||||
MouseHiliteMode = DECMode(1001)
|
|
||||||
|
|
||||||
EnableMouseHilite = "\x1b[?1001h"
|
// Button Event Mouse Tracking is essentially the same as [ModeMouseNormal],
|
||||||
DisableMouseHilite = "\x1b[?1001l"
|
|
||||||
RequestMouseHilite = "\x1b[?1001$p"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Button Event Mouse Tracking is essentially the same as [NormalMouseMode],
|
|
||||||
// but it also reports button-motion events when a button is pressed.
|
// but it also reports button-motion events when a button is pressed.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
const (
|
const (
|
||||||
ButtonEventMouseMode = DECMode(1002)
|
ModeMouseButtonEvent = DECMode(1002)
|
||||||
|
|
||||||
SetButtonEventMouseMode = "\x1b[?1002h"
|
SetModeMouseButtonEvent = "\x1b[?1002h"
|
||||||
ResetButtonEventMouseMode = "\x1b[?1002l"
|
ResetModeMouseButtonEvent = "\x1b[?1002l"
|
||||||
RequestButtonEventMouseMode = "\x1b[?1002$p"
|
RequestModeMouseButtonEvent = "\x1b[?1002$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cell Motion Mouse Tracking is a mode that determines whether the mouse
|
// Any Event Mouse Tracking is the same as [ModeMouseButtonEvent], except that
|
||||||
// reports on button press, release, and motion events.
|
|
||||||
//
|
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
|
||||||
//
|
|
||||||
// Deprecated: use [ButtonEventMouseMode] instead.
|
|
||||||
const (
|
|
||||||
MouseCellMotionMode = DECMode(1002)
|
|
||||||
|
|
||||||
EnableMouseCellMotion = "\x1b[?1002h"
|
|
||||||
DisableMouseCellMotion = "\x1b[?1002l"
|
|
||||||
RequestMouseCellMotion = "\x1b[?1002$p"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Any Event Mouse Tracking is the same as [ButtonEventMouseMode], except that
|
|
||||||
// all motion events are reported even if no mouse buttons are pressed.
|
// all motion events are reported even if no mouse buttons are pressed.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
const (
|
const (
|
||||||
AnyEventMouseMode = DECMode(1003)
|
ModeMouseAnyEvent = DECMode(1003)
|
||||||
|
|
||||||
SetAnyEventMouseMode = "\x1b[?1003h"
|
SetModeMouseAnyEvent = "\x1b[?1003h"
|
||||||
ResetAnyEventMouseMode = "\x1b[?1003l"
|
ResetModeMouseAnyEvent = "\x1b[?1003l"
|
||||||
RequestAnyEventMouseMode = "\x1b[?1003$p"
|
RequestModeMouseAnyEvent = "\x1b[?1003$p"
|
||||||
)
|
|
||||||
|
|
||||||
// All Mouse Tracking is a mode that determines whether the mouse reports on
|
|
||||||
// button press, release, motion, and highlight events.
|
|
||||||
//
|
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
|
||||||
//
|
|
||||||
// Deprecated: use [AnyEventMouseMode] instead.
|
|
||||||
const (
|
|
||||||
MouseAllMotionMode = DECMode(1003)
|
|
||||||
|
|
||||||
EnableMouseAllMotion = "\x1b[?1003h"
|
|
||||||
DisableMouseAllMotion = "\x1b[?1003l"
|
|
||||||
RequestMouseAllMotion = "\x1b[?1003$p"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Focus Event Mode is a mode that determines whether the terminal reports focus
|
// Focus Event Mode is a mode that determines whether the terminal reports focus
|
||||||
@ -564,22 +498,11 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Focus-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Focus-Tracking
|
||||||
const (
|
const (
|
||||||
FocusEventMode = DECMode(1004)
|
ModeFocusEvent = DECMode(1004)
|
||||||
|
|
||||||
SetFocusEventMode = "\x1b[?1004h"
|
SetModeFocusEvent = "\x1b[?1004h"
|
||||||
ResetFocusEventMode = "\x1b[?1004l"
|
ResetModeFocusEvent = "\x1b[?1004l"
|
||||||
RequestFocusEventMode = "\x1b[?1004$p"
|
RequestModeFocusEvent = "\x1b[?1004$p"
|
||||||
)
|
|
||||||
|
|
||||||
// Deprecated: use [SetFocusEventMode], [ResetFocusEventMode], and
|
|
||||||
// [RequestFocusEventMode] instead.
|
|
||||||
// Focus reporting mode constants.
|
|
||||||
const (
|
|
||||||
ReportFocusMode = DECMode(1004) //nolint:revive // grouped constants
|
|
||||||
|
|
||||||
EnableReportFocus = "\x1b[?1004h"
|
|
||||||
DisableReportFocus = "\x1b[?1004l"
|
|
||||||
RequestReportFocus = "\x1b[?1004$p"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SGR Extended Mouse Mode is a mode that changes the mouse tracking encoding
|
// SGR Extended Mouse Mode is a mode that changes the mouse tracking encoding
|
||||||
@ -589,24 +512,15 @@ const (
|
|||||||
//
|
//
|
||||||
// CSI < Cb ; Cx ; Cy M
|
// CSI < Cb ; Cx ; Cy M
|
||||||
//
|
//
|
||||||
// Where Cb is the same as [NormalMouseMode], and Cx and Cy are the x and y.
|
// Where Cb is the same as [ModeMouseNormal], and Cx and Cy are the x and y.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
const (
|
const (
|
||||||
SgrExtMouseMode = DECMode(1006)
|
ModeMouseExtSgr = DECMode(1006)
|
||||||
|
|
||||||
SetSgrExtMouseMode = "\x1b[?1006h"
|
SetModeMouseExtSgr = "\x1b[?1006h"
|
||||||
ResetSgrExtMouseMode = "\x1b[?1006l"
|
ResetModeMouseExtSgr = "\x1b[?1006l"
|
||||||
RequestSgrExtMouseMode = "\x1b[?1006$p"
|
RequestModeMouseExtSgr = "\x1b[?1006$p"
|
||||||
)
|
|
||||||
|
|
||||||
// Deprecated: use [SgrExtMouseMode] [SetSgrExtMouseMode],
|
|
||||||
// [ResetSgrExtMouseMode], and [RequestSgrExtMouseMode] instead.
|
|
||||||
const (
|
|
||||||
MouseSgrExtMode = DECMode(1006) //nolint:revive // grouped constants
|
|
||||||
EnableMouseSgrExt = "\x1b[?1006h"
|
|
||||||
DisableMouseSgrExt = "\x1b[?1006l"
|
|
||||||
RequestMouseSgrExt = "\x1b[?1006$p"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// UTF-8 Extended Mouse Mode is a mode that changes the mouse tracking encoding
|
// UTF-8 Extended Mouse Mode is a mode that changes the mouse tracking encoding
|
||||||
@ -614,11 +528,11 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
const (
|
const (
|
||||||
Utf8ExtMouseMode = DECMode(1005)
|
ModeMouseExtUtf8 = DECMode(1005)
|
||||||
|
|
||||||
SetUtf8ExtMouseMode = "\x1b[?1005h"
|
SetModeMouseExtUtf8 = "\x1b[?1005h"
|
||||||
ResetUtf8ExtMouseMode = "\x1b[?1005l"
|
ResetModeMouseExtUtf8 = "\x1b[?1005l"
|
||||||
RequestUtf8ExtMouseMode = "\x1b[?1005$p"
|
RequestModeMouseExtUtf8 = "\x1b[?1005$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// URXVT Extended Mouse Mode is a mode that changes the mouse tracking encoding
|
// URXVT Extended Mouse Mode is a mode that changes the mouse tracking encoding
|
||||||
@ -626,25 +540,25 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
const (
|
const (
|
||||||
UrxvtExtMouseMode = DECMode(1015)
|
ModeMouseExtUrxvt = DECMode(1015)
|
||||||
|
|
||||||
SetUrxvtExtMouseMode = "\x1b[?1015h"
|
SetModeMouseExtUrxvt = "\x1b[?1015h"
|
||||||
ResetUrxvtExtMouseMode = "\x1b[?1015l"
|
ResetModeMouseExtUrxvt = "\x1b[?1015l"
|
||||||
RequestUrxvtExtMouseMode = "\x1b[?1015$p"
|
RequestModeMouseExtUrxvt = "\x1b[?1015$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SGR Pixel Extended Mouse Mode is a mode that changes the mouse tracking
|
// SGR Pixel Extended Mouse Mode is a mode that changes the mouse tracking
|
||||||
// encoding to use SGR parameters with pixel coordinates.
|
// encoding to use SGR parameters with pixel coordinates.
|
||||||
//
|
//
|
||||||
// This is similar to [SgrExtMouseMode], but also reports pixel coordinates.
|
// This is similar to [ModeMouseExtSgr], but also reports pixel coordinates.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
const (
|
const (
|
||||||
SgrPixelExtMouseMode = DECMode(1016)
|
ModeMouseExtSgrPixel = DECMode(1016)
|
||||||
|
|
||||||
SetSgrPixelExtMouseMode = "\x1b[?1016h"
|
SetModeMouseExtSgrPixel = "\x1b[?1016h"
|
||||||
ResetSgrPixelExtMouseMode = "\x1b[?1016l"
|
ResetModeMouseExtSgrPixel = "\x1b[?1016l"
|
||||||
RequestSgrPixelExtMouseMode = "\x1b[?1016$p"
|
RequestModeMouseExtSgrPixel = "\x1b[?1016$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Alternate Screen Mode is a mode that determines whether the alternate screen
|
// Alternate Screen Mode is a mode that determines whether the alternate screen
|
||||||
@ -653,11 +567,11 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
||||||
const (
|
const (
|
||||||
AltScreenMode = DECMode(1047)
|
ModeAltScreen = DECMode(1047)
|
||||||
|
|
||||||
SetAltScreenMode = "\x1b[?1047h"
|
SetModeAltScreen = "\x1b[?1047h"
|
||||||
ResetAltScreenMode = "\x1b[?1047l"
|
ResetModeAltScreen = "\x1b[?1047l"
|
||||||
RequestAltScreenMode = "\x1b[?1047$p"
|
RequestModeAltScreen = "\x1b[?1047$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Save Cursor Mode is a mode that saves the cursor position.
|
// Save Cursor Mode is a mode that saves the cursor position.
|
||||||
@ -665,42 +579,24 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
||||||
const (
|
const (
|
||||||
SaveCursorMode = DECMode(1048)
|
ModeSaveCursor = DECMode(1048)
|
||||||
|
|
||||||
SetSaveCursorMode = "\x1b[?1048h"
|
SetModeSaveCursor = "\x1b[?1048h"
|
||||||
ResetSaveCursorMode = "\x1b[?1048l"
|
ResetModeSaveCursor = "\x1b[?1048l"
|
||||||
RequestSaveCursorMode = "\x1b[?1048$p"
|
RequestModeSaveCursor = "\x1b[?1048$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Alternate Screen Save Cursor Mode is a mode that saves the cursor position as in
|
// Alternate Screen Save Cursor Mode is a mode that saves the cursor position as in
|
||||||
// [SaveCursorMode], switches to the alternate screen buffer as in [AltScreenMode],
|
// [ModeSaveCursor], switches to the alternate screen buffer as in [ModeAltScreen],
|
||||||
// and clears the screen on switch.
|
// and clears the screen on switch.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
||||||
const (
|
const (
|
||||||
AltScreenSaveCursorMode = DECMode(1049)
|
ModeAltScreenSaveCursor = DECMode(1049)
|
||||||
|
|
||||||
SetAltScreenSaveCursorMode = "\x1b[?1049h"
|
SetModeAltScreenSaveCursor = "\x1b[?1049h"
|
||||||
ResetAltScreenSaveCursorMode = "\x1b[?1049l"
|
ResetModeAltScreenSaveCursor = "\x1b[?1049l"
|
||||||
RequestAltScreenSaveCursorMode = "\x1b[?1049$p"
|
RequestModeAltScreenSaveCursor = "\x1b[?1049$p"
|
||||||
)
|
|
||||||
|
|
||||||
// Alternate Screen Buffer is a mode that determines whether the alternate screen
|
|
||||||
// buffer is active.
|
|
||||||
//
|
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
|
||||||
//
|
|
||||||
// Deprecated: use [AltScreenSaveCursorMode] instead.
|
|
||||||
const (
|
|
||||||
AltScreenBufferMode = DECMode(1049)
|
|
||||||
|
|
||||||
SetAltScreenBufferMode = "\x1b[?1049h"
|
|
||||||
ResetAltScreenBufferMode = "\x1b[?1049l"
|
|
||||||
RequestAltScreenBufferMode = "\x1b[?1049$p"
|
|
||||||
|
|
||||||
EnableAltScreenBuffer = "\x1b[?1049h"
|
|
||||||
DisableAltScreenBuffer = "\x1b[?1049l"
|
|
||||||
RequestAltScreenBuffer = "\x1b[?1049$p"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bracketed Paste Mode is a mode that determines whether pasted text is
|
// Bracketed Paste Mode is a mode that determines whether pasted text is
|
||||||
@ -709,19 +605,11 @@ const (
|
|||||||
// See: https://cirw.in/blog/bracketed-paste
|
// See: https://cirw.in/blog/bracketed-paste
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode
|
||||||
const (
|
const (
|
||||||
BracketedPasteMode = DECMode(2004)
|
ModeBracketedPaste = DECMode(2004)
|
||||||
|
|
||||||
SetBracketedPasteMode = "\x1b[?2004h"
|
SetModeBracketedPaste = "\x1b[?2004h"
|
||||||
ResetBracketedPasteMode = "\x1b[?2004l"
|
ResetModeBracketedPaste = "\x1b[?2004l"
|
||||||
RequestBracketedPasteMode = "\x1b[?2004$p"
|
RequestModeBracketedPaste = "\x1b[?2004$p"
|
||||||
)
|
|
||||||
|
|
||||||
// Deprecated: use [SetBracketedPasteMode], [ResetBracketedPasteMode], and
|
|
||||||
// [RequestBracketedPasteMode] instead.
|
|
||||||
const (
|
|
||||||
EnableBracketedPaste = "\x1b[?2004h" //nolint:revive // grouped constants
|
|
||||||
DisableBracketedPaste = "\x1b[?2004l"
|
|
||||||
RequestBracketedPaste = "\x1b[?2004$p"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Synchronized Output Mode is a mode that determines whether output is
|
// Synchronized Output Mode is a mode that determines whether output is
|
||||||
@ -729,23 +617,11 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036
|
// See: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036
|
||||||
const (
|
const (
|
||||||
SynchronizedOutputMode = DECMode(2026)
|
ModeSynchronizedOutput = DECMode(2026)
|
||||||
|
|
||||||
SetSynchronizedOutputMode = "\x1b[?2026h"
|
SetModeSynchronizedOutput = "\x1b[?2026h"
|
||||||
ResetSynchronizedOutputMode = "\x1b[?2026l"
|
ResetModeSynchronizedOutput = "\x1b[?2026l"
|
||||||
RequestSynchronizedOutputMode = "\x1b[?2026$p"
|
RequestModeSynchronizedOutput = "\x1b[?2026$p"
|
||||||
)
|
|
||||||
|
|
||||||
// Synchronized Output Mode. See [SynchronizedOutputMode].
|
|
||||||
//
|
|
||||||
// Deprecated: use [SynchronizedOutputMode], [SetSynchronizedOutputMode], and
|
|
||||||
// [ResetSynchronizedOutputMode], and [RequestSynchronizedOutputMode] instead.
|
|
||||||
const (
|
|
||||||
SyncdOutputMode = DECMode(2026)
|
|
||||||
|
|
||||||
EnableSyncdOutput = "\x1b[?2026h"
|
|
||||||
DisableSyncdOutput = "\x1b[?2026l"
|
|
||||||
RequestSyncdOutput = "\x1b[?2026$p"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Unicode Core Mode is a mode that determines whether the terminal should use
|
// Unicode Core Mode is a mode that determines whether the terminal should use
|
||||||
@ -754,41 +630,16 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://github.com/contour-terminal/terminal-unicode-core
|
// See: https://github.com/contour-terminal/terminal-unicode-core
|
||||||
const (
|
const (
|
||||||
UnicodeCoreMode = DECMode(2027)
|
ModeUnicodeCore = DECMode(2027)
|
||||||
|
|
||||||
SetUnicodeCoreMode = "\x1b[?2027h"
|
SetModeUnicodeCore = "\x1b[?2027h"
|
||||||
ResetUnicodeCoreMode = "\x1b[?2027l"
|
ResetModeUnicodeCore = "\x1b[?2027l"
|
||||||
RequestUnicodeCoreMode = "\x1b[?2027$p"
|
RequestModeUnicodeCore = "\x1b[?2027$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Grapheme Clustering Mode is a mode that determines whether the terminal
|
|
||||||
// should look for grapheme clusters instead of single runes in the rendered
|
|
||||||
// text. This makes the terminal properly render combining characters such as
|
|
||||||
// emojis.
|
|
||||||
//
|
//
|
||||||
// See: https://github.com/contour-terminal/terminal-unicode-core
|
|
||||||
//
|
|
||||||
// Deprecated: use [GraphemeClusteringMode], [SetUnicodeCoreMode],
|
|
||||||
// [ResetUnicodeCoreMode], and [RequestUnicodeCoreMode] instead.
|
|
||||||
const (
|
|
||||||
GraphemeClusteringMode = DECMode(2027)
|
|
||||||
|
|
||||||
SetGraphemeClusteringMode = "\x1b[?2027h"
|
// ModeLightDark is a mode that enables reporting the operating system's color
|
||||||
ResetGraphemeClusteringMode = "\x1b[?2027l"
|
|
||||||
RequestGraphemeClusteringMode = "\x1b[?2027$p"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Grapheme Clustering Mode. See [GraphemeClusteringMode].
|
|
||||||
//
|
|
||||||
// Deprecated: use [SetUnicodeCoreMode], [ResetUnicodeCoreMode], and
|
|
||||||
// [RequestUnicodeCoreMode] instead.
|
|
||||||
const (
|
|
||||||
EnableGraphemeClustering = "\x1b[?2027h"
|
|
||||||
DisableGraphemeClustering = "\x1b[?2027l"
|
|
||||||
RequestGraphemeClustering = "\x1b[?2027$p"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LightDarkMode is a mode that enables reporting the operating system's color
|
|
||||||
// scheme (light or dark) preference. It reports the color scheme as a [DSR]
|
// scheme (light or dark) preference. It reports the color scheme as a [DSR]
|
||||||
// and [LightDarkReport] escape sequences encoded as follows:
|
// and [LightDarkReport] escape sequences encoded as follows:
|
||||||
//
|
//
|
||||||
@ -802,14 +653,14 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://contour-terminal.org/vt-extensions/color-palette-update-notifications/
|
// See: https://contour-terminal.org/vt-extensions/color-palette-update-notifications/
|
||||||
const (
|
const (
|
||||||
LightDarkMode = DECMode(2031)
|
ModeLightDark = DECMode(2031)
|
||||||
|
|
||||||
SetLightDarkMode = "\x1b[?2031h"
|
SetModeLightDark = "\x1b[?2031h"
|
||||||
ResetLightDarkMode = "\x1b[?2031l"
|
ResetModeLightDark = "\x1b[?2031l"
|
||||||
RequestLightDarkMode = "\x1b[?2031$p"
|
RequestModeLightDark = "\x1b[?2031$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InBandResizeMode is a mode that reports terminal resize events as escape
|
// ModeInBandResize is a mode that reports terminal resize events as escape
|
||||||
// sequences. This is useful for systems that do not support [SIGWINCH] like
|
// sequences. This is useful for systems that do not support [SIGWINCH] like
|
||||||
// Windows.
|
// Windows.
|
||||||
//
|
//
|
||||||
@ -819,11 +670,11 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83
|
// See: https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83
|
||||||
const (
|
const (
|
||||||
InBandResizeMode = DECMode(2048)
|
ModeInBandResize = DECMode(2048)
|
||||||
|
|
||||||
SetInBandResizeMode = "\x1b[?2048h"
|
SetModeInBandResize = "\x1b[?2048h"
|
||||||
ResetInBandResizeMode = "\x1b[?2048l"
|
ResetModeInBandResize = "\x1b[?2048l"
|
||||||
RequestInBandResizeMode = "\x1b[?2048$p"
|
RequestModeInBandResize = "\x1b[?2048$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Win32Input is a mode that determines whether input is processed by the
|
// Win32Input is a mode that determines whether input is processed by the
|
||||||
@ -831,17 +682,9 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md
|
// See: https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md
|
||||||
const (
|
const (
|
||||||
Win32InputMode = DECMode(9001)
|
ModeWin32Input = DECMode(9001)
|
||||||
|
|
||||||
SetWin32InputMode = "\x1b[?9001h"
|
SetModeWin32Input = "\x1b[?9001h"
|
||||||
ResetWin32InputMode = "\x1b[?9001l"
|
ResetModeWin32Input = "\x1b[?9001l"
|
||||||
RequestWin32InputMode = "\x1b[?9001$p"
|
RequestModeWin32Input = "\x1b[?9001$p"
|
||||||
)
|
|
||||||
|
|
||||||
// Deprecated: use [SetWin32InputMode], [ResetWin32InputMode], and
|
|
||||||
// [RequestWin32InputMode] instead.
|
|
||||||
const (
|
|
||||||
EnableWin32Input = "\x1b[?9001h" //nolint:revive // grouped constants
|
|
||||||
DisableWin32Input = "\x1b[?9001l"
|
|
||||||
RequestWin32Input = "\x1b[?9001$p"
|
|
||||||
)
|
)
|
||||||
|
|||||||
495
vendor/github.com/charmbracelet/x/ansi/mode_deprecated.go
generated
vendored
Normal file
495
vendor/github.com/charmbracelet/x/ansi/mode_deprecated.go
generated
vendored
Normal file
@ -0,0 +1,495 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
// Keyboard Action Mode (KAM) controls locking of the keyboard.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeKeyboardAction] instead.
|
||||||
|
const (
|
||||||
|
KeyboardActionMode = ANSIMode(2)
|
||||||
|
|
||||||
|
SetKeyboardActionMode = "\x1b[2h"
|
||||||
|
ResetKeyboardActionMode = "\x1b[2l"
|
||||||
|
RequestKeyboardActionMode = "\x1b[2$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Insert/Replace Mode (IRM) determines whether characters are inserted or replaced.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeInsertReplace] instead.
|
||||||
|
const (
|
||||||
|
InsertReplaceMode = ANSIMode(4)
|
||||||
|
|
||||||
|
SetInsertReplaceMode = "\x1b[4h"
|
||||||
|
ResetInsertReplaceMode = "\x1b[4l"
|
||||||
|
RequestInsertReplaceMode = "\x1b[4$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BiDirectional Support Mode (BDSM) determines whether the terminal supports bidirectional text.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeBiDirectionalSupport] instead.
|
||||||
|
const (
|
||||||
|
BiDirectionalSupportMode = ANSIMode(8)
|
||||||
|
|
||||||
|
SetBiDirectionalSupportMode = "\x1b[8h"
|
||||||
|
ResetBiDirectionalSupportMode = "\x1b[8l"
|
||||||
|
RequestBiDirectionalSupportMode = "\x1b[8$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Send Receive Mode (SRM) or Local Echo Mode determines whether the terminal echoes characters.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeSendReceive] instead.
|
||||||
|
const (
|
||||||
|
SendReceiveMode = ANSIMode(12)
|
||||||
|
LocalEchoMode = SendReceiveMode
|
||||||
|
|
||||||
|
SetSendReceiveMode = "\x1b[12h"
|
||||||
|
ResetSendReceiveMode = "\x1b[12l"
|
||||||
|
RequestSendReceiveMode = "\x1b[12$p"
|
||||||
|
|
||||||
|
SetLocalEchoMode = "\x1b[12h"
|
||||||
|
ResetLocalEchoMode = "\x1b[12l"
|
||||||
|
RequestLocalEchoMode = "\x1b[12$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Line Feed/New Line Mode (LNM) determines whether the terminal interprets line feed as new line.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeLineFeedNewLine] instead.
|
||||||
|
const (
|
||||||
|
LineFeedNewLineMode = ANSIMode(20)
|
||||||
|
|
||||||
|
SetLineFeedNewLineMode = "\x1b[20h"
|
||||||
|
ResetLineFeedNewLineMode = "\x1b[20l"
|
||||||
|
RequestLineFeedNewLineMode = "\x1b[20$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cursor Keys Mode (DECCKM) determines whether cursor keys send ANSI or application sequences.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeCursorKeys] instead.
|
||||||
|
const (
|
||||||
|
CursorKeysMode = DECMode(1)
|
||||||
|
|
||||||
|
SetCursorKeysMode = "\x1b[?1h"
|
||||||
|
ResetCursorKeysMode = "\x1b[?1l"
|
||||||
|
RequestCursorKeysMode = "\x1b[?1$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cursor Keys mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [SetModeCursorKeys] and [ResetModeCursorKeys] instead.
|
||||||
|
const (
|
||||||
|
EnableCursorKeys = "\x1b[?1h"
|
||||||
|
DisableCursorKeys = "\x1b[?1l"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Origin Mode (DECOM) determines whether the cursor moves to home or margin position.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeOrigin] instead.
|
||||||
|
const (
|
||||||
|
OriginMode = DECMode(6)
|
||||||
|
|
||||||
|
SetOriginMode = "\x1b[?6h"
|
||||||
|
ResetOriginMode = "\x1b[?6l"
|
||||||
|
RequestOriginMode = "\x1b[?6$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Auto Wrap Mode (DECAWM) determines whether the cursor wraps to the next line.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeAutoWrap] instead.
|
||||||
|
const (
|
||||||
|
AutoWrapMode = DECMode(7)
|
||||||
|
|
||||||
|
SetAutoWrapMode = "\x1b[?7h"
|
||||||
|
ResetAutoWrapMode = "\x1b[?7l"
|
||||||
|
RequestAutoWrapMode = "\x1b[?7$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// X10 Mouse Mode determines whether the mouse reports on button presses.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseX10] instead.
|
||||||
|
const (
|
||||||
|
X10MouseMode = DECMode(9)
|
||||||
|
|
||||||
|
SetX10MouseMode = "\x1b[?9h"
|
||||||
|
ResetX10MouseMode = "\x1b[?9l"
|
||||||
|
RequestX10MouseMode = "\x1b[?9$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Text Cursor Enable Mode (DECTCEM) shows/hides the cursor.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeTextCursorEnable] instead.
|
||||||
|
const (
|
||||||
|
TextCursorEnableMode = DECMode(25)
|
||||||
|
|
||||||
|
SetTextCursorEnableMode = "\x1b[?25h"
|
||||||
|
ResetTextCursorEnableMode = "\x1b[?25l"
|
||||||
|
RequestTextCursorEnableMode = "\x1b[?25$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Text Cursor Enable mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [SetModeTextCursorEnable] and [ResetModeTextCursorEnable] instead.
|
||||||
|
const (
|
||||||
|
CursorEnableMode = DECMode(25)
|
||||||
|
RequestCursorVisibility = "\x1b[?25$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Numeric Keypad Mode (DECNKM) determines whether the keypad sends application or numeric sequences.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeNumericKeypad] instead.
|
||||||
|
const (
|
||||||
|
NumericKeypadMode = DECMode(66)
|
||||||
|
|
||||||
|
SetNumericKeypadMode = "\x1b[?66h"
|
||||||
|
ResetNumericKeypadMode = "\x1b[?66l"
|
||||||
|
RequestNumericKeypadMode = "\x1b[?66$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Backarrow Key Mode (DECBKM) determines whether the backspace key sends backspace or delete.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeBackarrowKey] instead.
|
||||||
|
const (
|
||||||
|
BackarrowKeyMode = DECMode(67)
|
||||||
|
|
||||||
|
SetBackarrowKeyMode = "\x1b[?67h"
|
||||||
|
ResetBackarrowKeyMode = "\x1b[?67l"
|
||||||
|
RequestBackarrowKeyMode = "\x1b[?67$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Left Right Margin Mode (DECLRMM) determines whether left and right margins can be set.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeLeftRightMargin] instead.
|
||||||
|
const (
|
||||||
|
LeftRightMarginMode = DECMode(69)
|
||||||
|
|
||||||
|
SetLeftRightMarginMode = "\x1b[?69h"
|
||||||
|
ResetLeftRightMarginMode = "\x1b[?69l"
|
||||||
|
RequestLeftRightMarginMode = "\x1b[?69$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Normal Mouse Mode determines whether the mouse reports on button presses and releases.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseNormal] instead.
|
||||||
|
const (
|
||||||
|
NormalMouseMode = DECMode(1000)
|
||||||
|
|
||||||
|
SetNormalMouseMode = "\x1b[?1000h"
|
||||||
|
ResetNormalMouseMode = "\x1b[?1000l"
|
||||||
|
RequestNormalMouseMode = "\x1b[?1000$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VT Mouse Tracking mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseNormal] instead.
|
||||||
|
const (
|
||||||
|
MouseMode = DECMode(1000)
|
||||||
|
|
||||||
|
EnableMouse = "\x1b[?1000h"
|
||||||
|
DisableMouse = "\x1b[?1000l"
|
||||||
|
RequestMouse = "\x1b[?1000$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Highlight Mouse Tracking determines whether the mouse reports on button presses and highlighted cells.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseHighlight] instead.
|
||||||
|
const (
|
||||||
|
HighlightMouseMode = DECMode(1001)
|
||||||
|
|
||||||
|
SetHighlightMouseMode = "\x1b[?1001h"
|
||||||
|
ResetHighlightMouseMode = "\x1b[?1001l"
|
||||||
|
RequestHighlightMouseMode = "\x1b[?1001$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VT Hilite Mouse Tracking mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseHighlight] instead.
|
||||||
|
const (
|
||||||
|
MouseHiliteMode = DECMode(1001)
|
||||||
|
|
||||||
|
EnableMouseHilite = "\x1b[?1001h"
|
||||||
|
DisableMouseHilite = "\x1b[?1001l"
|
||||||
|
RequestMouseHilite = "\x1b[?1001$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Button Event Mouse Tracking reports button-motion events when a button is pressed.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseButtonEvent] instead.
|
||||||
|
const (
|
||||||
|
ButtonEventMouseMode = DECMode(1002)
|
||||||
|
|
||||||
|
SetButtonEventMouseMode = "\x1b[?1002h"
|
||||||
|
ResetButtonEventMouseMode = "\x1b[?1002l"
|
||||||
|
RequestButtonEventMouseMode = "\x1b[?1002$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cell Motion Mouse Tracking mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseButtonEvent] instead.
|
||||||
|
const (
|
||||||
|
MouseCellMotionMode = DECMode(1002)
|
||||||
|
|
||||||
|
EnableMouseCellMotion = "\x1b[?1002h"
|
||||||
|
DisableMouseCellMotion = "\x1b[?1002l"
|
||||||
|
RequestMouseCellMotion = "\x1b[?1002$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Any Event Mouse Tracking reports all motion events.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseAnyEvent] instead.
|
||||||
|
const (
|
||||||
|
AnyEventMouseMode = DECMode(1003)
|
||||||
|
|
||||||
|
SetAnyEventMouseMode = "\x1b[?1003h"
|
||||||
|
ResetAnyEventMouseMode = "\x1b[?1003l"
|
||||||
|
RequestAnyEventMouseMode = "\x1b[?1003$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// All Mouse Tracking mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseAnyEvent] instead.
|
||||||
|
const (
|
||||||
|
MouseAllMotionMode = DECMode(1003)
|
||||||
|
|
||||||
|
EnableMouseAllMotion = "\x1b[?1003h"
|
||||||
|
DisableMouseAllMotion = "\x1b[?1003l"
|
||||||
|
RequestMouseAllMotion = "\x1b[?1003$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Focus Event Mode determines whether the terminal reports focus and blur events.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeFocusEvent] instead.
|
||||||
|
const (
|
||||||
|
FocusEventMode = DECMode(1004)
|
||||||
|
|
||||||
|
SetFocusEventMode = "\x1b[?1004h"
|
||||||
|
ResetFocusEventMode = "\x1b[?1004l"
|
||||||
|
RequestFocusEventMode = "\x1b[?1004$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Focus reporting mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [SetModeFocusEvent], [ResetModeFocusEvent], and
|
||||||
|
// [RequestModeFocusEvent] instead.
|
||||||
|
const (
|
||||||
|
ReportFocusMode = DECMode(1004)
|
||||||
|
|
||||||
|
EnableReportFocus = "\x1b[?1004h"
|
||||||
|
DisableReportFocus = "\x1b[?1004l"
|
||||||
|
RequestReportFocus = "\x1b[?1004$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UTF-8 Extended Mouse Mode changes the mouse tracking encoding to use UTF-8 parameters.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseExtUtf8] instead.
|
||||||
|
const (
|
||||||
|
Utf8ExtMouseMode = DECMode(1005)
|
||||||
|
|
||||||
|
SetUtf8ExtMouseMode = "\x1b[?1005h"
|
||||||
|
ResetUtf8ExtMouseMode = "\x1b[?1005l"
|
||||||
|
RequestUtf8ExtMouseMode = "\x1b[?1005$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SGR Extended Mouse Mode changes the mouse tracking encoding to use SGR parameters.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseExtSgr] instead.
|
||||||
|
const (
|
||||||
|
SgrExtMouseMode = DECMode(1006)
|
||||||
|
|
||||||
|
SetSgrExtMouseMode = "\x1b[?1006h"
|
||||||
|
ResetSgrExtMouseMode = "\x1b[?1006l"
|
||||||
|
RequestSgrExtMouseMode = "\x1b[?1006$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mouse SGR Extended mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseExtSgr], [SetModeMouseExtSgr],
|
||||||
|
// [ResetModeMouseExtSgr], and [RequestModeMouseExtSgr] instead.
|
||||||
|
const (
|
||||||
|
MouseSgrExtMode = DECMode(1006)
|
||||||
|
EnableMouseSgrExt = "\x1b[?1006h"
|
||||||
|
DisableMouseSgrExt = "\x1b[?1006l"
|
||||||
|
RequestMouseSgrExt = "\x1b[?1006$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// URXVT Extended Mouse Mode changes the mouse tracking encoding to use an alternate encoding.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseUrxvtExt] instead.
|
||||||
|
const (
|
||||||
|
UrxvtExtMouseMode = DECMode(1015)
|
||||||
|
|
||||||
|
SetUrxvtExtMouseMode = "\x1b[?1015h"
|
||||||
|
ResetUrxvtExtMouseMode = "\x1b[?1015l"
|
||||||
|
RequestUrxvtExtMouseMode = "\x1b[?1015$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SGR Pixel Extended Mouse Mode changes the mouse tracking encoding to use SGR parameters with pixel coordinates.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeMouseExtSgrPixel] instead.
|
||||||
|
const (
|
||||||
|
SgrPixelExtMouseMode = DECMode(1016)
|
||||||
|
|
||||||
|
SetSgrPixelExtMouseMode = "\x1b[?1016h"
|
||||||
|
ResetSgrPixelExtMouseMode = "\x1b[?1016l"
|
||||||
|
RequestSgrPixelExtMouseMode = "\x1b[?1016$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Alternate Screen Mode determines whether the alternate screen buffer is active.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeAltScreen] instead.
|
||||||
|
const (
|
||||||
|
AltScreenMode = DECMode(1047)
|
||||||
|
|
||||||
|
SetAltScreenMode = "\x1b[?1047h"
|
||||||
|
ResetAltScreenMode = "\x1b[?1047l"
|
||||||
|
RequestAltScreenMode = "\x1b[?1047$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Save Cursor Mode saves the cursor position.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeSaveCursor] instead.
|
||||||
|
const (
|
||||||
|
SaveCursorMode = DECMode(1048)
|
||||||
|
|
||||||
|
SetSaveCursorMode = "\x1b[?1048h"
|
||||||
|
ResetSaveCursorMode = "\x1b[?1048l"
|
||||||
|
RequestSaveCursorMode = "\x1b[?1048$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Alternate Screen Save Cursor Mode saves the cursor position and switches to alternate screen.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeAltScreenSaveCursor] instead.
|
||||||
|
const (
|
||||||
|
AltScreenSaveCursorMode = DECMode(1049)
|
||||||
|
|
||||||
|
SetAltScreenSaveCursorMode = "\x1b[?1049h"
|
||||||
|
ResetAltScreenSaveCursorMode = "\x1b[?1049l"
|
||||||
|
RequestAltScreenSaveCursorMode = "\x1b[?1049$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Alternate Screen Buffer mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeAltScreenSaveCursor] instead.
|
||||||
|
const (
|
||||||
|
AltScreenBufferMode = DECMode(1049)
|
||||||
|
|
||||||
|
SetAltScreenBufferMode = "\x1b[?1049h"
|
||||||
|
ResetAltScreenBufferMode = "\x1b[?1049l"
|
||||||
|
RequestAltScreenBufferMode = "\x1b[?1049$p"
|
||||||
|
|
||||||
|
EnableAltScreenBuffer = "\x1b[?1049h"
|
||||||
|
DisableAltScreenBuffer = "\x1b[?1049l"
|
||||||
|
RequestAltScreenBuffer = "\x1b[?1049$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bracketed Paste Mode determines whether pasted text is bracketed with escape sequences.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeBracketedPaste] instead.
|
||||||
|
const (
|
||||||
|
BracketedPasteMode = DECMode(2004)
|
||||||
|
|
||||||
|
SetBracketedPasteMode = "\x1b[?2004h"
|
||||||
|
ResetBracketedPasteMode = "\x1b[?2004l"
|
||||||
|
RequestBracketedPasteMode = "\x1b[?2004$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: use [SetModeBracketedPaste], [ResetModeBracketedPaste], and
|
||||||
|
// [RequestModeBracketedPaste] instead.
|
||||||
|
const (
|
||||||
|
EnableBracketedPaste = "\x1b[?2004h" //nolint:revive
|
||||||
|
DisableBracketedPaste = "\x1b[?2004l"
|
||||||
|
RequestBracketedPaste = "\x1b[?2004$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Synchronized Output Mode determines whether output is synchronized with the terminal.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeSynchronizedOutput] instead.
|
||||||
|
const (
|
||||||
|
SynchronizedOutputMode = DECMode(2026)
|
||||||
|
|
||||||
|
SetSynchronizedOutputMode = "\x1b[?2026h"
|
||||||
|
ResetSynchronizedOutputMode = "\x1b[?2026l"
|
||||||
|
RequestSynchronizedOutputMode = "\x1b[?2026$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Synchronized output mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeSynchronizedOutput], [SetModeSynchronizedOutput],
|
||||||
|
// [ResetModeSynchronizedOutput], and [RequestModeSynchronizedOutput] instead.
|
||||||
|
const (
|
||||||
|
SyncdOutputMode = DECMode(2026)
|
||||||
|
|
||||||
|
EnableSyncdOutput = "\x1b[?2026h"
|
||||||
|
DisableSyncdOutput = "\x1b[?2026l"
|
||||||
|
RequestSyncdOutput = "\x1b[?2026$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unicode Core Mode determines whether the terminal uses Unicode grapheme clustering.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeUnicodeCore] instead.
|
||||||
|
const (
|
||||||
|
UnicodeCoreMode = DECMode(2027)
|
||||||
|
|
||||||
|
SetUnicodeCoreMode = "\x1b[?2027h"
|
||||||
|
ResetUnicodeCoreMode = "\x1b[?2027l"
|
||||||
|
RequestUnicodeCoreMode = "\x1b[?2027$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Grapheme Clustering Mode determines whether the terminal looks for grapheme clusters.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeUnicodeCore], [SetModeUnicodeCore],
|
||||||
|
// [ResetModeUnicodeCore], and [RequestModeUnicodeCore] instead.
|
||||||
|
const (
|
||||||
|
GraphemeClusteringMode = DECMode(2027)
|
||||||
|
|
||||||
|
SetGraphemeClusteringMode = "\x1b[?2027h"
|
||||||
|
ResetGraphemeClusteringMode = "\x1b[?2027l"
|
||||||
|
RequestGraphemeClusteringMode = "\x1b[?2027$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unicode Core mode.
|
||||||
|
//
|
||||||
|
// Deprecated: use [SetModeUnicodeCore], [ResetModeUnicodeCore], and
|
||||||
|
// [RequestModeUnicodeCore] instead.
|
||||||
|
const (
|
||||||
|
EnableGraphemeClustering = "\x1b[?2027h"
|
||||||
|
DisableGraphemeClustering = "\x1b[?2027l"
|
||||||
|
RequestGraphemeClustering = "\x1b[?2027$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Light Dark Mode enables reporting the operating system's color scheme preference.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeLightDark] instead.
|
||||||
|
const (
|
||||||
|
LightDarkMode = DECMode(2031)
|
||||||
|
|
||||||
|
SetLightDarkMode = "\x1b[?2031h"
|
||||||
|
ResetLightDarkMode = "\x1b[?2031l"
|
||||||
|
RequestLightDarkMode = "\x1b[?2031$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// In Band Resize Mode reports terminal resize events as escape sequences.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeInBandResize] instead.
|
||||||
|
const (
|
||||||
|
InBandResizeMode = DECMode(2048)
|
||||||
|
|
||||||
|
SetInBandResizeMode = "\x1b[?2048h"
|
||||||
|
ResetInBandResizeMode = "\x1b[?2048l"
|
||||||
|
RequestInBandResizeMode = "\x1b[?2048$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Win32Input determines whether input is processed by the Win32 console and Conpty.
|
||||||
|
//
|
||||||
|
// Deprecated: use [ModeWin32Input] instead.
|
||||||
|
const (
|
||||||
|
Win32InputMode = DECMode(9001)
|
||||||
|
|
||||||
|
SetWin32InputMode = "\x1b[?9001h"
|
||||||
|
ResetWin32InputMode = "\x1b[?9001l"
|
||||||
|
RequestWin32InputMode = "\x1b[?9001$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: use [SetModeWin32Input], [ResetModeWin32Input], and
|
||||||
|
// [RequestModeWin32Input] instead.
|
||||||
|
const (
|
||||||
|
EnableWin32Input = "\x1b[?9001h" //nolint:revive
|
||||||
|
DisableWin32Input = "\x1b[?9001l"
|
||||||
|
RequestWin32Input = "\x1b[?9001$p"
|
||||||
|
)
|
||||||
2
vendor/github.com/charmbracelet/x/ansi/mouse.go
generated
vendored
2
vendor/github.com/charmbracelet/x/ansi/mouse.go
generated
vendored
@ -134,7 +134,7 @@ func EncodeMouseButton(b MouseButton, motion, shift, alt, ctrl bool) (m byte) {
|
|||||||
m |= bitMotion
|
m |= bitMotion
|
||||||
}
|
}
|
||||||
|
|
||||||
return //nolint:nakedret
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// x10Offset is the offset for X10 mouse events.
|
// x10Offset is the offset for X10 mouse events.
|
||||||
|
|||||||
19
vendor/github.com/charmbracelet/x/ansi/notification.go
generated
vendored
19
vendor/github.com/charmbracelet/x/ansi/notification.go
generated
vendored
@ -1,5 +1,10 @@
|
|||||||
package ansi
|
package ansi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// Notify sends a desktop notification using iTerm's OSC 9.
|
// Notify sends a desktop notification using iTerm's OSC 9.
|
||||||
//
|
//
|
||||||
// OSC 9 ; Mc ST
|
// OSC 9 ; Mc ST
|
||||||
@ -11,3 +16,17 @@ package ansi
|
|||||||
func Notify(s string) string {
|
func Notify(s string) string {
|
||||||
return "\x1b]9;" + s + "\x07"
|
return "\x1b]9;" + s + "\x07"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DesktopNotification sends a desktop notification based on the extensible OSC
|
||||||
|
// 99 escape code.
|
||||||
|
//
|
||||||
|
// OSC 99 ; <metadata> ; <payload> ST
|
||||||
|
// OSC 99 ; <metadata> ; <payload> BEL
|
||||||
|
//
|
||||||
|
// Where <metadata> is a colon-separated list of key-value pairs, and
|
||||||
|
// <payload> is the notification body.
|
||||||
|
//
|
||||||
|
// See: https://sw.kovidgoyal.net/kitty/desktop-notifications/
|
||||||
|
func DesktopNotification(payload string, metadata ...string) string {
|
||||||
|
return fmt.Sprintf("\x1b]99;%s;%s\x07", strings.Join(metadata, ":"), payload)
|
||||||
|
}
|
||||||
|
|||||||
33
vendor/github.com/charmbracelet/x/ansi/parser_decode.go
generated
vendored
33
vendor/github.com/charmbracelet/x/ansi/parser_decode.go
generated
vendored
@ -4,8 +4,7 @@ import (
|
|||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/charmbracelet/x/ansi/parser"
|
"github.com/charmbracelet/x/ansi/parser"
|
||||||
"github.com/mattn/go-runewidth"
|
"github.com/clipperhouse/uax29/v2/graphemes"
|
||||||
"github.com/rivo/uniseg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// State represents the state of the ANSI escape sequence parser used by
|
// State represents the state of the ANSI escape sequence parser used by
|
||||||
@ -176,10 +175,7 @@ func decodeSequence[T string | []byte](m Method, b T, state State, p *Parser) (s
|
|||||||
}
|
}
|
||||||
|
|
||||||
if utf8.RuneStart(c) {
|
if utf8.RuneStart(c) {
|
||||||
seq, _, width, _ = FirstGraphemeCluster(b, -1)
|
seq, width = FirstGraphemeCluster(b, m)
|
||||||
if m == WcWidth {
|
|
||||||
width = runewidth.StringWidth(string(seq))
|
|
||||||
}
|
|
||||||
i += len(seq)
|
i += len(seq)
|
||||||
return b[:i], width, i, NormalState
|
return b[:i], width, i, NormalState
|
||||||
}
|
}
|
||||||
@ -434,17 +430,22 @@ func HasEscPrefix[T string | []byte](b T) bool {
|
|||||||
return len(b) > 0 && b[0] == ESC
|
return len(b) > 0 && b[0] == ESC
|
||||||
}
|
}
|
||||||
|
|
||||||
// FirstGraphemeCluster returns the first grapheme cluster in the given string or byte slice.
|
// FirstGraphemeCluster returns the first grapheme cluster in the given string
|
||||||
// This is a syntactic sugar function that wraps
|
// or byte slice, and its monospace display width.
|
||||||
// uniseg.FirstGraphemeClusterInString and uniseg.FirstGraphemeCluster.
|
func FirstGraphemeCluster[T string | []byte](b T, m Method) (T, int) {
|
||||||
func FirstGraphemeCluster[T string | []byte](b T, state int) (T, T, int, int) {
|
|
||||||
switch b := any(b).(type) {
|
switch b := any(b).(type) {
|
||||||
case string:
|
case string:
|
||||||
cluster, rest, width, newState := uniseg.FirstGraphemeClusterInString(b, state)
|
cluster := graphemes.FromString(b).First()
|
||||||
return T(cluster), T(rest), width, newState
|
if m == WcWidth {
|
||||||
|
return T(cluster), wcOptions.StringWidth(cluster)
|
||||||
|
}
|
||||||
|
return T(cluster), dwOptions.String(cluster)
|
||||||
case []byte:
|
case []byte:
|
||||||
cluster, rest, width, newState := uniseg.FirstGraphemeCluster(b, state)
|
cluster := graphemes.FromBytes(b).First()
|
||||||
return T(cluster), T(rest), width, newState
|
if m == WcWidth {
|
||||||
|
return T(cluster), wcOptions.StringWidth(string(cluster))
|
||||||
|
}
|
||||||
|
return T(cluster), dwOptions.Bytes(cluster)
|
||||||
}
|
}
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
@ -490,7 +491,7 @@ func Command(prefix, inter, final byte) (c int) {
|
|||||||
c = int(final)
|
c = int(final)
|
||||||
c |= int(prefix) << parser.PrefixShift
|
c |= int(prefix) << parser.PrefixShift
|
||||||
c |= int(inter) << parser.IntermedShift
|
c |= int(inter) << parser.IntermedShift
|
||||||
return
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Param represents a sequence parameter. Sequence parameters with
|
// Param represents a sequence parameter. Sequence parameters with
|
||||||
@ -520,5 +521,5 @@ func Parameter(p int, hasMore bool) (s int) {
|
|||||||
if hasMore {
|
if hasMore {
|
||||||
s |= parser.HasMoreFlag
|
s |= parser.HasMoreFlag
|
||||||
}
|
}
|
||||||
return
|
return s
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/charmbracelet/x/ansi/parser_sync.go
generated
vendored
2
vendor/github.com/charmbracelet/x/ansi/parser_sync.go
generated
vendored
@ -10,7 +10,7 @@ var parserPool = sync.Pool{
|
|||||||
New: func() any {
|
New: func() any {
|
||||||
p := NewParser()
|
p := NewParser()
|
||||||
p.SetParamsSize(parser.MaxParamsSize)
|
p.SetParamsSize(parser.MaxParamsSize)
|
||||||
p.SetDataSize(1024 * 1024 * 4) // 4MB of data buffer
|
p.SetDataSize(1024 * 4) // 4KB of data buffer
|
||||||
return p
|
return p
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
110
vendor/github.com/charmbracelet/x/ansi/sgr.go
generated
vendored
110
vendor/github.com/charmbracelet/x/ansi/sgr.go
generated
vendored
@ -21,59 +21,59 @@ func SGR(ps ...Attr) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var attrStrings = map[int]string{
|
var attrStrings = map[int]string{
|
||||||
ResetAttr: resetAttr,
|
AttrReset: attrReset,
|
||||||
BoldAttr: boldAttr,
|
AttrBold: attrBold,
|
||||||
FaintAttr: faintAttr,
|
AttrFaint: attrFaint,
|
||||||
ItalicAttr: italicAttr,
|
AttrItalic: attrItalic,
|
||||||
UnderlineAttr: underlineAttr,
|
AttrUnderline: attrUnderline,
|
||||||
SlowBlinkAttr: slowBlinkAttr,
|
AttrBlink: attrBlink,
|
||||||
RapidBlinkAttr: rapidBlinkAttr,
|
AttrRapidBlink: attrRapidBlink,
|
||||||
ReverseAttr: reverseAttr,
|
AttrReverse: attrReverse,
|
||||||
ConcealAttr: concealAttr,
|
AttrConceal: attrConceal,
|
||||||
StrikethroughAttr: strikethroughAttr,
|
AttrStrikethrough: attrStrikethrough,
|
||||||
NormalIntensityAttr: normalIntensityAttr,
|
AttrNormalIntensity: attrNormalIntensity,
|
||||||
NoItalicAttr: noItalicAttr,
|
AttrNoItalic: attrNoItalic,
|
||||||
NoUnderlineAttr: noUnderlineAttr,
|
AttrNoUnderline: attrNoUnderline,
|
||||||
NoBlinkAttr: noBlinkAttr,
|
AttrNoBlink: attrNoBlink,
|
||||||
NoReverseAttr: noReverseAttr,
|
AttrNoReverse: attrNoReverse,
|
||||||
NoConcealAttr: noConcealAttr,
|
AttrNoConceal: attrNoConceal,
|
||||||
NoStrikethroughAttr: noStrikethroughAttr,
|
AttrNoStrikethrough: attrNoStrikethrough,
|
||||||
BlackForegroundColorAttr: blackForegroundColorAttr,
|
AttrBlackForegroundColor: attrBlackForegroundColor,
|
||||||
RedForegroundColorAttr: redForegroundColorAttr,
|
AttrRedForegroundColor: attrRedForegroundColor,
|
||||||
GreenForegroundColorAttr: greenForegroundColorAttr,
|
AttrGreenForegroundColor: attrGreenForegroundColor,
|
||||||
YellowForegroundColorAttr: yellowForegroundColorAttr,
|
AttrYellowForegroundColor: attrYellowForegroundColor,
|
||||||
BlueForegroundColorAttr: blueForegroundColorAttr,
|
AttrBlueForegroundColor: attrBlueForegroundColor,
|
||||||
MagentaForegroundColorAttr: magentaForegroundColorAttr,
|
AttrMagentaForegroundColor: attrMagentaForegroundColor,
|
||||||
CyanForegroundColorAttr: cyanForegroundColorAttr,
|
AttrCyanForegroundColor: attrCyanForegroundColor,
|
||||||
WhiteForegroundColorAttr: whiteForegroundColorAttr,
|
AttrWhiteForegroundColor: attrWhiteForegroundColor,
|
||||||
ExtendedForegroundColorAttr: extendedForegroundColorAttr,
|
AttrExtendedForegroundColor: attrExtendedForegroundColor,
|
||||||
DefaultForegroundColorAttr: defaultForegroundColorAttr,
|
AttrDefaultForegroundColor: attrDefaultForegroundColor,
|
||||||
BlackBackgroundColorAttr: blackBackgroundColorAttr,
|
AttrBlackBackgroundColor: attrBlackBackgroundColor,
|
||||||
RedBackgroundColorAttr: redBackgroundColorAttr,
|
AttrRedBackgroundColor: attrRedBackgroundColor,
|
||||||
GreenBackgroundColorAttr: greenBackgroundColorAttr,
|
AttrGreenBackgroundColor: attrGreenBackgroundColor,
|
||||||
YellowBackgroundColorAttr: yellowBackgroundColorAttr,
|
AttrYellowBackgroundColor: attrYellowBackgroundColor,
|
||||||
BlueBackgroundColorAttr: blueBackgroundColorAttr,
|
AttrBlueBackgroundColor: attrBlueBackgroundColor,
|
||||||
MagentaBackgroundColorAttr: magentaBackgroundColorAttr,
|
AttrMagentaBackgroundColor: attrMagentaBackgroundColor,
|
||||||
CyanBackgroundColorAttr: cyanBackgroundColorAttr,
|
AttrCyanBackgroundColor: attrCyanBackgroundColor,
|
||||||
WhiteBackgroundColorAttr: whiteBackgroundColorAttr,
|
AttrWhiteBackgroundColor: attrWhiteBackgroundColor,
|
||||||
ExtendedBackgroundColorAttr: extendedBackgroundColorAttr,
|
AttrExtendedBackgroundColor: attrExtendedBackgroundColor,
|
||||||
DefaultBackgroundColorAttr: defaultBackgroundColorAttr,
|
AttrDefaultBackgroundColor: attrDefaultBackgroundColor,
|
||||||
ExtendedUnderlineColorAttr: extendedUnderlineColorAttr,
|
AttrExtendedUnderlineColor: attrExtendedUnderlineColor,
|
||||||
DefaultUnderlineColorAttr: defaultUnderlineColorAttr,
|
AttrDefaultUnderlineColor: attrDefaultUnderlineColor,
|
||||||
BrightBlackForegroundColorAttr: brightBlackForegroundColorAttr,
|
AttrBrightBlackForegroundColor: attrBrightBlackForegroundColor,
|
||||||
BrightRedForegroundColorAttr: brightRedForegroundColorAttr,
|
AttrBrightRedForegroundColor: attrBrightRedForegroundColor,
|
||||||
BrightGreenForegroundColorAttr: brightGreenForegroundColorAttr,
|
AttrBrightGreenForegroundColor: attrBrightGreenForegroundColor,
|
||||||
BrightYellowForegroundColorAttr: brightYellowForegroundColorAttr,
|
AttrBrightYellowForegroundColor: attrBrightYellowForegroundColor,
|
||||||
BrightBlueForegroundColorAttr: brightBlueForegroundColorAttr,
|
AttrBrightBlueForegroundColor: attrBrightBlueForegroundColor,
|
||||||
BrightMagentaForegroundColorAttr: brightMagentaForegroundColorAttr,
|
AttrBrightMagentaForegroundColor: attrBrightMagentaForegroundColor,
|
||||||
BrightCyanForegroundColorAttr: brightCyanForegroundColorAttr,
|
AttrBrightCyanForegroundColor: attrBrightCyanForegroundColor,
|
||||||
BrightWhiteForegroundColorAttr: brightWhiteForegroundColorAttr,
|
AttrBrightWhiteForegroundColor: attrBrightWhiteForegroundColor,
|
||||||
BrightBlackBackgroundColorAttr: brightBlackBackgroundColorAttr,
|
AttrBrightBlackBackgroundColor: attrBrightBlackBackgroundColor,
|
||||||
BrightRedBackgroundColorAttr: brightRedBackgroundColorAttr,
|
AttrBrightRedBackgroundColor: attrBrightRedBackgroundColor,
|
||||||
BrightGreenBackgroundColorAttr: brightGreenBackgroundColorAttr,
|
AttrBrightGreenBackgroundColor: attrBrightGreenBackgroundColor,
|
||||||
BrightYellowBackgroundColorAttr: brightYellowBackgroundColorAttr,
|
AttrBrightYellowBackgroundColor: attrBrightYellowBackgroundColor,
|
||||||
BrightBlueBackgroundColorAttr: brightBlueBackgroundColorAttr,
|
AttrBrightBlueBackgroundColor: attrBrightBlueBackgroundColor,
|
||||||
BrightMagentaBackgroundColorAttr: brightMagentaBackgroundColorAttr,
|
AttrBrightMagentaBackgroundColor: attrBrightMagentaBackgroundColor,
|
||||||
BrightCyanBackgroundColorAttr: brightCyanBackgroundColorAttr,
|
AttrBrightCyanBackgroundColor: attrBrightCyanBackgroundColor,
|
||||||
BrightWhiteBackgroundColorAttr: brightWhiteBackgroundColorAttr,
|
AttrBrightWhiteBackgroundColor: attrBrightWhiteBackgroundColor,
|
||||||
}
|
}
|
||||||
|
|||||||
630
vendor/github.com/charmbracelet/x/ansi/style.go
generated
vendored
630
vendor/github.com/charmbracelet/x/ansi/style.go
generated
vendored
@ -17,7 +17,9 @@ type Attr = int
|
|||||||
// Style represents an ANSI SGR (Select Graphic Rendition) style.
|
// Style represents an ANSI SGR (Select Graphic Rendition) style.
|
||||||
type Style []string
|
type Style []string
|
||||||
|
|
||||||
// NewStyle returns a new style with the given attributes.
|
// NewStyle returns a new style with the given attributes. Attributes are SGR
|
||||||
|
// (Select Graphic Rendition) codes that control text formatting like bold,
|
||||||
|
// italic, colors, etc.
|
||||||
func NewStyle(attrs ...Attr) Style {
|
func NewStyle(attrs ...Attr) Style {
|
||||||
if len(attrs) == 0 {
|
if len(attrs) == 0 {
|
||||||
return Style{}
|
return Style{}
|
||||||
@ -46,7 +48,8 @@ func (s Style) String() string {
|
|||||||
return "\x1b[" + strings.Join(s, ";") + "m"
|
return "\x1b[" + strings.Join(s, ";") + "m"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Styled returns a styled string with the given style applied.
|
// Styled returns a styled string with the given style applied. The style is
|
||||||
|
// applied at the beginning and reset at the end of the string.
|
||||||
func (s Style) Styled(str string) string {
|
func (s Style) Styled(str string) string {
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return str
|
return str
|
||||||
@ -54,309 +57,446 @@ func (s Style) Styled(str string) string {
|
|||||||
return s.String() + str + ResetStyle
|
return s.String() + str + ResetStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset appends the reset style attribute to the style.
|
// Reset appends the reset style attribute to the style. This resets all
|
||||||
|
// formatting attributes to their defaults.
|
||||||
func (s Style) Reset() Style {
|
func (s Style) Reset() Style {
|
||||||
return append(s, resetAttr)
|
return append(s, attrReset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bold appends the bold style attribute to the style.
|
// Bold appends the bold or normal intensity style attribute to the style.
|
||||||
|
// You can use [Style.Normal] to reset to normal intensity.
|
||||||
func (s Style) Bold() Style {
|
func (s Style) Bold() Style {
|
||||||
return append(s, boldAttr)
|
return append(s, attrBold)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Faint appends the faint style attribute to the style.
|
// Faint appends the faint or normal intensity style attribute to the style.
|
||||||
|
// You can use [Style.Normal] to reset to normal intensity.
|
||||||
func (s Style) Faint() Style {
|
func (s Style) Faint() Style {
|
||||||
return append(s, faintAttr)
|
return append(s, attrFaint)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Italic appends the italic style attribute to the style.
|
// Italic appends the italic or no italic style attribute to the style.
|
||||||
func (s Style) Italic() Style {
|
// When v is true, text is rendered in italic. When false, italic is disabled.
|
||||||
return append(s, italicAttr)
|
func (s Style) Italic(v bool) Style {
|
||||||
|
if v {
|
||||||
|
return append(s, attrItalic)
|
||||||
|
}
|
||||||
|
return append(s, attrNoItalic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Underline appends the underline style attribute to the style.
|
// Underline appends the underline or no underline style attribute to the style.
|
||||||
func (s Style) Underline() Style {
|
// When v is true, text is underlined. When false, underline is disabled.
|
||||||
return append(s, underlineAttr)
|
func (s Style) Underline(v bool) Style {
|
||||||
|
if v {
|
||||||
|
return append(s, attrUnderline)
|
||||||
|
}
|
||||||
|
return append(s, attrNoUnderline)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnderlineStyle appends the underline style attribute to the style.
|
// UnderlineStyle appends the underline style attribute to the style.
|
||||||
func (s Style) UnderlineStyle(u UnderlineStyle) Style {
|
// Supports various underline styles including single, double, curly, dotted,
|
||||||
|
// and dashed.
|
||||||
|
func (s Style) UnderlineStyle(u Underline) Style {
|
||||||
switch u {
|
switch u {
|
||||||
case NoUnderlineStyle:
|
case UnderlineNone:
|
||||||
return s.NoUnderline()
|
return s.Underline(false)
|
||||||
case SingleUnderlineStyle:
|
case UnderlineSingle:
|
||||||
return s.Underline()
|
return s.Underline(true)
|
||||||
case DoubleUnderlineStyle:
|
case UnderlineDouble:
|
||||||
return append(s, doubleUnderlineStyle)
|
return append(s, underlineDouble)
|
||||||
case CurlyUnderlineStyle:
|
case UnderlineCurly:
|
||||||
return append(s, curlyUnderlineStyle)
|
return append(s, underlineCurly)
|
||||||
case DottedUnderlineStyle:
|
case UnderlineDotted:
|
||||||
return append(s, dottedUnderlineStyle)
|
return append(s, underlineDotted)
|
||||||
case DashedUnderlineStyle:
|
case UnderlineDashed:
|
||||||
return append(s, dashedUnderlineStyle)
|
return append(s, underlineDashed)
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// DoubleUnderline appends the double underline style attribute to the style.
|
// Blink appends the slow blink or no blink style attribute to the style.
|
||||||
// This is a convenience method for UnderlineStyle(DoubleUnderlineStyle).
|
// When v is true, text blinks slowly (less than 150 per minute). When false,
|
||||||
func (s Style) DoubleUnderline() Style {
|
// blinking is disabled.
|
||||||
return s.UnderlineStyle(DoubleUnderlineStyle)
|
func (s Style) Blink(v bool) Style {
|
||||||
|
if v {
|
||||||
|
return append(s, attrBlink)
|
||||||
|
}
|
||||||
|
return append(s, attrNoBlink)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurlyUnderline appends the curly underline style attribute to the style.
|
// RapidBlink appends the rapid blink or no blink style attribute to the style.
|
||||||
// This is a convenience method for UnderlineStyle(CurlyUnderlineStyle).
|
// When v is true, text blinks rapidly (150+ per minute). When false, blinking
|
||||||
func (s Style) CurlyUnderline() Style {
|
// is disabled.
|
||||||
return s.UnderlineStyle(CurlyUnderlineStyle)
|
//
|
||||||
|
// Note that this is not widely supported in terminal emulators.
|
||||||
|
func (s Style) RapidBlink(v bool) Style {
|
||||||
|
if v {
|
||||||
|
return append(s, attrRapidBlink)
|
||||||
|
}
|
||||||
|
return append(s, attrNoBlink)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DottedUnderline appends the dotted underline style attribute to the style.
|
// Reverse appends the reverse or no reverse style attribute to the style.
|
||||||
// This is a convenience method for UnderlineStyle(DottedUnderlineStyle).
|
// When v is true, foreground and background colors are swapped. When false,
|
||||||
func (s Style) DottedUnderline() Style {
|
// reverse video is disabled.
|
||||||
return s.UnderlineStyle(DottedUnderlineStyle)
|
func (s Style) Reverse(v bool) Style {
|
||||||
|
if v {
|
||||||
|
return append(s, attrReverse)
|
||||||
|
}
|
||||||
|
return append(s, attrNoReverse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DashedUnderline appends the dashed underline style attribute to the style.
|
// Conceal appends the conceal or no conceal style attribute to the style.
|
||||||
// This is a convenience method for UnderlineStyle(DashedUnderlineStyle).
|
// When v is true, text is hidden/concealed. When false, concealment is
|
||||||
func (s Style) DashedUnderline() Style {
|
// disabled.
|
||||||
return s.UnderlineStyle(DashedUnderlineStyle)
|
func (s Style) Conceal(v bool) Style {
|
||||||
|
if v {
|
||||||
|
return append(s, attrConceal)
|
||||||
|
}
|
||||||
|
return append(s, attrNoConceal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SlowBlink appends the slow blink style attribute to the style.
|
// Strikethrough appends the strikethrough or no strikethrough style attribute
|
||||||
func (s Style) SlowBlink() Style {
|
// to the style. When v is true, text is rendered with a horizontal line through
|
||||||
return append(s, slowBlinkAttr)
|
// it. When false, strikethrough is disabled.
|
||||||
|
func (s Style) Strikethrough(v bool) Style {
|
||||||
|
if v {
|
||||||
|
return append(s, attrStrikethrough)
|
||||||
|
}
|
||||||
|
return append(s, attrNoStrikethrough)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RapidBlink appends the rapid blink style attribute to the style.
|
// Normal appends the normal intensity style attribute to the style. This
|
||||||
func (s Style) RapidBlink() Style {
|
// resets [Style.Bold] and [Style.Faint] attributes.
|
||||||
return append(s, rapidBlinkAttr)
|
func (s Style) Normal() Style {
|
||||||
}
|
return append(s, attrNormalIntensity)
|
||||||
|
|
||||||
// Reverse appends the reverse style attribute to the style.
|
|
||||||
func (s Style) Reverse() Style {
|
|
||||||
return append(s, reverseAttr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conceal appends the conceal style attribute to the style.
|
|
||||||
func (s Style) Conceal() Style {
|
|
||||||
return append(s, concealAttr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strikethrough appends the strikethrough style attribute to the style.
|
|
||||||
func (s Style) Strikethrough() Style {
|
|
||||||
return append(s, strikethroughAttr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NormalIntensity appends the normal intensity style attribute to the style.
|
|
||||||
func (s Style) NormalIntensity() Style {
|
|
||||||
return append(s, normalIntensityAttr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoItalic appends the no italic style attribute to the style.
|
// NoItalic appends the no italic style attribute to the style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Style.Italic](false) instead.
|
||||||
func (s Style) NoItalic() Style {
|
func (s Style) NoItalic() Style {
|
||||||
return append(s, noItalicAttr)
|
return append(s, attrNoItalic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoUnderline appends the no underline style attribute to the style.
|
// NoUnderline appends the no underline style attribute to the style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Style.Underline](false) instead.
|
||||||
func (s Style) NoUnderline() Style {
|
func (s Style) NoUnderline() Style {
|
||||||
return append(s, noUnderlineAttr)
|
return append(s, attrNoUnderline)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoBlink appends the no blink style attribute to the style.
|
// NoBlink appends the no blink style attribute to the style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Style.Blink](false) or [Style.RapidBlink](false) instead.
|
||||||
func (s Style) NoBlink() Style {
|
func (s Style) NoBlink() Style {
|
||||||
return append(s, noBlinkAttr)
|
return append(s, attrNoBlink)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoReverse appends the no reverse style attribute to the style.
|
// NoReverse appends the no reverse style attribute to the style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Style.Reverse](false) instead.
|
||||||
func (s Style) NoReverse() Style {
|
func (s Style) NoReverse() Style {
|
||||||
return append(s, noReverseAttr)
|
return append(s, attrNoReverse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoConceal appends the no conceal style attribute to the style.
|
// NoConceal appends the no conceal style attribute to the style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Style.Conceal](false) instead.
|
||||||
func (s Style) NoConceal() Style {
|
func (s Style) NoConceal() Style {
|
||||||
return append(s, noConcealAttr)
|
return append(s, attrNoConceal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoStrikethrough appends the no strikethrough style attribute to the style.
|
// NoStrikethrough appends the no strikethrough style attribute to the style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Style.Strikethrough](false) instead.
|
||||||
func (s Style) NoStrikethrough() Style {
|
func (s Style) NoStrikethrough() Style {
|
||||||
return append(s, noStrikethroughAttr)
|
return append(s, attrNoStrikethrough)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultForegroundColor appends the default foreground color style attribute to the style.
|
// DefaultForegroundColor appends the default foreground color style attribute to the style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Style.ForegroundColor](nil) instead.
|
||||||
func (s Style) DefaultForegroundColor() Style {
|
func (s Style) DefaultForegroundColor() Style {
|
||||||
return append(s, defaultForegroundColorAttr)
|
return append(s, attrDefaultForegroundColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultBackgroundColor appends the default background color style attribute to the style.
|
// DefaultBackgroundColor appends the default background color style attribute to the style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Style.BackgroundColor](nil) instead.
|
||||||
func (s Style) DefaultBackgroundColor() Style {
|
func (s Style) DefaultBackgroundColor() Style {
|
||||||
return append(s, defaultBackgroundColorAttr)
|
return append(s, attrDefaultBackgroundColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultUnderlineColor appends the default underline color style attribute to the style.
|
// DefaultUnderlineColor appends the default underline color style attribute to the style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Style.UnderlineColor](nil) instead.
|
||||||
func (s Style) DefaultUnderlineColor() Style {
|
func (s Style) DefaultUnderlineColor() Style {
|
||||||
return append(s, defaultUnderlineColorAttr)
|
return append(s, attrDefaultUnderlineColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForegroundColor appends the foreground color style attribute to the style.
|
// ForegroundColor appends the foreground color style attribute to the style.
|
||||||
|
// If c is nil, the default foreground color is used. Supports [BasicColor],
|
||||||
|
// [IndexedColor] (256-color), and [color.Color] (24-bit RGB).
|
||||||
func (s Style) ForegroundColor(c Color) Style {
|
func (s Style) ForegroundColor(c Color) Style {
|
||||||
|
if c == nil {
|
||||||
|
return append(s, attrDefaultForegroundColor)
|
||||||
|
}
|
||||||
return append(s, foregroundColorString(c))
|
return append(s, foregroundColorString(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BackgroundColor appends the background color style attribute to the style.
|
// BackgroundColor appends the background color style attribute to the style.
|
||||||
|
// If c is nil, the default background color is used. Supports [BasicColor],
|
||||||
|
// [IndexedColor] (256-color), and [color.Color] (24-bit RGB).
|
||||||
func (s Style) BackgroundColor(c Color) Style {
|
func (s Style) BackgroundColor(c Color) Style {
|
||||||
|
if c == nil {
|
||||||
|
return append(s, attrDefaultBackgroundColor)
|
||||||
|
}
|
||||||
return append(s, backgroundColorString(c))
|
return append(s, backgroundColorString(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnderlineColor appends the underline color style attribute to the style.
|
// UnderlineColor appends the underline color style attribute to the style.
|
||||||
|
// If c is nil, the default underline color is used. Supports [BasicColor],
|
||||||
|
// [IndexedColor] (256-color), and [color.Color] (24-bit RGB).
|
||||||
func (s Style) UnderlineColor(c Color) Style {
|
func (s Style) UnderlineColor(c Color) Style {
|
||||||
|
if c == nil {
|
||||||
|
return append(s, attrDefaultUnderlineColor)
|
||||||
|
}
|
||||||
return append(s, underlineColorString(c))
|
return append(s, underlineColorString(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Underline represents an ANSI SGR (Select Graphic Rendition) underline style.
|
||||||
|
type Underline = byte
|
||||||
|
|
||||||
// UnderlineStyle represents an ANSI SGR (Select Graphic Rendition) underline
|
// UnderlineStyle represents an ANSI SGR (Select Graphic Rendition) underline
|
||||||
// style.
|
// style.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Underline] instead.
|
||||||
type UnderlineStyle = byte
|
type UnderlineStyle = byte
|
||||||
|
|
||||||
const (
|
const (
|
||||||
doubleUnderlineStyle = "4:2"
|
underlineDouble = "4:2"
|
||||||
curlyUnderlineStyle = "4:3"
|
underlineCurly = "4:3"
|
||||||
dottedUnderlineStyle = "4:4"
|
underlineDotted = "4:4"
|
||||||
dashedUnderlineStyle = "4:5"
|
underlineDashed = "4:5"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Underline styles constants.
|
||||||
const (
|
const (
|
||||||
// NoUnderlineStyle is the default underline style.
|
UnderlineNone Underline = iota
|
||||||
NoUnderlineStyle UnderlineStyle = iota
|
UnderlineSingle
|
||||||
// SingleUnderlineStyle is a single underline style.
|
UnderlineDouble
|
||||||
|
UnderlineCurly
|
||||||
|
UnderlineDotted
|
||||||
|
UnderlineDashed
|
||||||
|
)
|
||||||
|
|
||||||
|
// Underline styles constants.
|
||||||
|
//
|
||||||
|
// Deprecated: use [UnderlineNone], [UnderlineSingle], etc. instead.
|
||||||
|
const (
|
||||||
|
NoUnderlineStyle Underline = iota
|
||||||
SingleUnderlineStyle
|
SingleUnderlineStyle
|
||||||
// DoubleUnderlineStyle is a double underline style.
|
|
||||||
DoubleUnderlineStyle
|
DoubleUnderlineStyle
|
||||||
// CurlyUnderlineStyle is a curly underline style.
|
|
||||||
CurlyUnderlineStyle
|
CurlyUnderlineStyle
|
||||||
// DottedUnderlineStyle is a dotted underline style.
|
|
||||||
DottedUnderlineStyle
|
DottedUnderlineStyle
|
||||||
// DashedUnderlineStyle is a dashed underline style.
|
|
||||||
DashedUnderlineStyle
|
DashedUnderlineStyle
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Underline styles constants.
|
||||||
|
//
|
||||||
|
// Deprecated: use [UnderlineNone], [UnderlineSingle], etc. instead.
|
||||||
|
const (
|
||||||
|
UnderlineStyleNone Underline = iota
|
||||||
|
UnderlineStyleSingle
|
||||||
|
UnderlineStyleDouble
|
||||||
|
UnderlineStyleCurly
|
||||||
|
UnderlineStyleDotted
|
||||||
|
UnderlineStyleDashed
|
||||||
|
)
|
||||||
|
|
||||||
// SGR (Select Graphic Rendition) style attributes.
|
// SGR (Select Graphic Rendition) style attributes.
|
||||||
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
||||||
const (
|
const (
|
||||||
ResetAttr Attr = 0
|
AttrReset Attr = 0
|
||||||
BoldAttr Attr = 1
|
AttrBold Attr = 1
|
||||||
FaintAttr Attr = 2
|
AttrFaint Attr = 2
|
||||||
ItalicAttr Attr = 3
|
AttrItalic Attr = 3
|
||||||
UnderlineAttr Attr = 4
|
AttrUnderline Attr = 4
|
||||||
SlowBlinkAttr Attr = 5
|
AttrBlink Attr = 5
|
||||||
RapidBlinkAttr Attr = 6
|
AttrRapidBlink Attr = 6
|
||||||
ReverseAttr Attr = 7
|
AttrReverse Attr = 7
|
||||||
ConcealAttr Attr = 8
|
AttrConceal Attr = 8
|
||||||
StrikethroughAttr Attr = 9
|
AttrStrikethrough Attr = 9
|
||||||
NormalIntensityAttr Attr = 22
|
AttrNormalIntensity Attr = 22
|
||||||
NoItalicAttr Attr = 23
|
AttrNoItalic Attr = 23
|
||||||
NoUnderlineAttr Attr = 24
|
AttrNoUnderline Attr = 24
|
||||||
NoBlinkAttr Attr = 25
|
AttrNoBlink Attr = 25
|
||||||
NoReverseAttr Attr = 27
|
AttrNoReverse Attr = 27
|
||||||
NoConcealAttr Attr = 28
|
AttrNoConceal Attr = 28
|
||||||
NoStrikethroughAttr Attr = 29
|
AttrNoStrikethrough Attr = 29
|
||||||
BlackForegroundColorAttr Attr = 30
|
AttrBlackForegroundColor Attr = 30
|
||||||
RedForegroundColorAttr Attr = 31
|
AttrRedForegroundColor Attr = 31
|
||||||
GreenForegroundColorAttr Attr = 32
|
AttrGreenForegroundColor Attr = 32
|
||||||
YellowForegroundColorAttr Attr = 33
|
AttrYellowForegroundColor Attr = 33
|
||||||
BlueForegroundColorAttr Attr = 34
|
AttrBlueForegroundColor Attr = 34
|
||||||
MagentaForegroundColorAttr Attr = 35
|
AttrMagentaForegroundColor Attr = 35
|
||||||
CyanForegroundColorAttr Attr = 36
|
AttrCyanForegroundColor Attr = 36
|
||||||
WhiteForegroundColorAttr Attr = 37
|
AttrWhiteForegroundColor Attr = 37
|
||||||
ExtendedForegroundColorAttr Attr = 38
|
AttrExtendedForegroundColor Attr = 38
|
||||||
DefaultForegroundColorAttr Attr = 39
|
AttrDefaultForegroundColor Attr = 39
|
||||||
BlackBackgroundColorAttr Attr = 40
|
AttrBlackBackgroundColor Attr = 40
|
||||||
RedBackgroundColorAttr Attr = 41
|
AttrRedBackgroundColor Attr = 41
|
||||||
GreenBackgroundColorAttr Attr = 42
|
AttrGreenBackgroundColor Attr = 42
|
||||||
YellowBackgroundColorAttr Attr = 43
|
AttrYellowBackgroundColor Attr = 43
|
||||||
BlueBackgroundColorAttr Attr = 44
|
AttrBlueBackgroundColor Attr = 44
|
||||||
MagentaBackgroundColorAttr Attr = 45
|
AttrMagentaBackgroundColor Attr = 45
|
||||||
CyanBackgroundColorAttr Attr = 46
|
AttrCyanBackgroundColor Attr = 46
|
||||||
WhiteBackgroundColorAttr Attr = 47
|
AttrWhiteBackgroundColor Attr = 47
|
||||||
ExtendedBackgroundColorAttr Attr = 48
|
AttrExtendedBackgroundColor Attr = 48
|
||||||
DefaultBackgroundColorAttr Attr = 49
|
AttrDefaultBackgroundColor Attr = 49
|
||||||
ExtendedUnderlineColorAttr Attr = 58
|
AttrExtendedUnderlineColor Attr = 58
|
||||||
DefaultUnderlineColorAttr Attr = 59
|
AttrDefaultUnderlineColor Attr = 59
|
||||||
BrightBlackForegroundColorAttr Attr = 90
|
AttrBrightBlackForegroundColor Attr = 90
|
||||||
BrightRedForegroundColorAttr Attr = 91
|
AttrBrightRedForegroundColor Attr = 91
|
||||||
BrightGreenForegroundColorAttr Attr = 92
|
AttrBrightGreenForegroundColor Attr = 92
|
||||||
BrightYellowForegroundColorAttr Attr = 93
|
AttrBrightYellowForegroundColor Attr = 93
|
||||||
BrightBlueForegroundColorAttr Attr = 94
|
AttrBrightBlueForegroundColor Attr = 94
|
||||||
BrightMagentaForegroundColorAttr Attr = 95
|
AttrBrightMagentaForegroundColor Attr = 95
|
||||||
BrightCyanForegroundColorAttr Attr = 96
|
AttrBrightCyanForegroundColor Attr = 96
|
||||||
BrightWhiteForegroundColorAttr Attr = 97
|
AttrBrightWhiteForegroundColor Attr = 97
|
||||||
BrightBlackBackgroundColorAttr Attr = 100
|
AttrBrightBlackBackgroundColor Attr = 100
|
||||||
BrightRedBackgroundColorAttr Attr = 101
|
AttrBrightRedBackgroundColor Attr = 101
|
||||||
BrightGreenBackgroundColorAttr Attr = 102
|
AttrBrightGreenBackgroundColor Attr = 102
|
||||||
BrightYellowBackgroundColorAttr Attr = 103
|
AttrBrightYellowBackgroundColor Attr = 103
|
||||||
BrightBlueBackgroundColorAttr Attr = 104
|
AttrBrightBlueBackgroundColor Attr = 104
|
||||||
BrightMagentaBackgroundColorAttr Attr = 105
|
AttrBrightMagentaBackgroundColor Attr = 105
|
||||||
BrightCyanBackgroundColorAttr Attr = 106
|
AttrBrightCyanBackgroundColor Attr = 106
|
||||||
BrightWhiteBackgroundColorAttr Attr = 107
|
AttrBrightWhiteBackgroundColor Attr = 107
|
||||||
|
|
||||||
RGBColorIntroducerAttr Attr = 2
|
AttrRGBColorIntroducer Attr = 2
|
||||||
ExtendedColorIntroducerAttr Attr = 5
|
AttrExtendedColorIntroducer Attr = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// SGR (Select Graphic Rendition) style attributes.
|
||||||
|
//
|
||||||
|
// Deprecated: use Attr* constants instead.
|
||||||
|
const (
|
||||||
|
ResetAttr = AttrReset
|
||||||
|
BoldAttr = AttrBold
|
||||||
|
FaintAttr = AttrFaint
|
||||||
|
ItalicAttr = AttrItalic
|
||||||
|
UnderlineAttr = AttrUnderline
|
||||||
|
SlowBlinkAttr = AttrBlink
|
||||||
|
RapidBlinkAttr = AttrRapidBlink
|
||||||
|
ReverseAttr = AttrReverse
|
||||||
|
ConcealAttr = AttrConceal
|
||||||
|
StrikethroughAttr = AttrStrikethrough
|
||||||
|
NormalIntensityAttr = AttrNormalIntensity
|
||||||
|
NoItalicAttr = AttrNoItalic
|
||||||
|
NoUnderlineAttr = AttrNoUnderline
|
||||||
|
NoBlinkAttr = AttrNoBlink
|
||||||
|
NoReverseAttr = AttrNoReverse
|
||||||
|
NoConcealAttr = AttrNoConceal
|
||||||
|
NoStrikethroughAttr = AttrNoStrikethrough
|
||||||
|
BlackForegroundColorAttr = AttrBlackForegroundColor
|
||||||
|
RedForegroundColorAttr = AttrRedForegroundColor
|
||||||
|
GreenForegroundColorAttr = AttrGreenForegroundColor
|
||||||
|
YellowForegroundColorAttr = AttrYellowForegroundColor
|
||||||
|
BlueForegroundColorAttr = AttrBlueForegroundColor
|
||||||
|
MagentaForegroundColorAttr = AttrMagentaForegroundColor
|
||||||
|
CyanForegroundColorAttr = AttrCyanForegroundColor
|
||||||
|
WhiteForegroundColorAttr = AttrWhiteForegroundColor
|
||||||
|
ExtendedForegroundColorAttr = AttrExtendedForegroundColor
|
||||||
|
DefaultForegroundColorAttr = AttrDefaultForegroundColor
|
||||||
|
BlackBackgroundColorAttr = AttrBlackBackgroundColor
|
||||||
|
RedBackgroundColorAttr = AttrRedBackgroundColor
|
||||||
|
GreenBackgroundColorAttr = AttrGreenBackgroundColor
|
||||||
|
YellowBackgroundColorAttr = AttrYellowBackgroundColor
|
||||||
|
BlueBackgroundColorAttr = AttrBlueBackgroundColor
|
||||||
|
MagentaBackgroundColorAttr = AttrMagentaBackgroundColor
|
||||||
|
CyanBackgroundColorAttr = AttrCyanBackgroundColor
|
||||||
|
WhiteBackgroundColorAttr = AttrWhiteBackgroundColor
|
||||||
|
ExtendedBackgroundColorAttr = AttrExtendedBackgroundColor
|
||||||
|
DefaultBackgroundColorAttr = AttrDefaultBackgroundColor
|
||||||
|
ExtendedUnderlineColorAttr = AttrExtendedUnderlineColor
|
||||||
|
DefaultUnderlineColorAttr = AttrDefaultUnderlineColor
|
||||||
|
BrightBlackForegroundColorAttr = AttrBrightBlackForegroundColor
|
||||||
|
BrightRedForegroundColorAttr = AttrBrightRedForegroundColor
|
||||||
|
BrightGreenForegroundColorAttr = AttrBrightGreenForegroundColor
|
||||||
|
BrightYellowForegroundColorAttr = AttrBrightYellowForegroundColor
|
||||||
|
BrightBlueForegroundColorAttr = AttrBrightBlueForegroundColor
|
||||||
|
BrightMagentaForegroundColorAttr = AttrBrightMagentaForegroundColor
|
||||||
|
BrightCyanForegroundColorAttr = AttrBrightCyanForegroundColor
|
||||||
|
BrightWhiteForegroundColorAttr = AttrBrightWhiteForegroundColor
|
||||||
|
BrightBlackBackgroundColorAttr = AttrBrightBlackBackgroundColor
|
||||||
|
BrightRedBackgroundColorAttr = AttrBrightRedBackgroundColor
|
||||||
|
BrightGreenBackgroundColorAttr = AttrBrightGreenBackgroundColor
|
||||||
|
BrightYellowBackgroundColorAttr = AttrBrightYellowBackgroundColor
|
||||||
|
BrightBlueBackgroundColorAttr = AttrBrightBlueBackgroundColor
|
||||||
|
BrightMagentaBackgroundColorAttr = AttrBrightMagentaBackgroundColor
|
||||||
|
BrightCyanBackgroundColorAttr = AttrBrightCyanBackgroundColor
|
||||||
|
BrightWhiteBackgroundColorAttr = AttrBrightWhiteBackgroundColor
|
||||||
|
RGBColorIntroducerAttr = AttrRGBColorIntroducer
|
||||||
|
ExtendedColorIntroducerAttr = AttrExtendedColorIntroducer
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
resetAttr = "0"
|
attrReset = "0"
|
||||||
boldAttr = "1"
|
attrBold = "1"
|
||||||
faintAttr = "2"
|
attrFaint = "2"
|
||||||
italicAttr = "3"
|
attrItalic = "3"
|
||||||
underlineAttr = "4"
|
attrUnderline = "4"
|
||||||
slowBlinkAttr = "5"
|
attrBlink = "5"
|
||||||
rapidBlinkAttr = "6"
|
attrRapidBlink = "6"
|
||||||
reverseAttr = "7"
|
attrReverse = "7"
|
||||||
concealAttr = "8"
|
attrConceal = "8"
|
||||||
strikethroughAttr = "9"
|
attrStrikethrough = "9"
|
||||||
normalIntensityAttr = "22"
|
attrNormalIntensity = "22"
|
||||||
noItalicAttr = "23"
|
attrNoItalic = "23"
|
||||||
noUnderlineAttr = "24"
|
attrNoUnderline = "24"
|
||||||
noBlinkAttr = "25"
|
attrNoBlink = "25"
|
||||||
noReverseAttr = "27"
|
attrNoReverse = "27"
|
||||||
noConcealAttr = "28"
|
attrNoConceal = "28"
|
||||||
noStrikethroughAttr = "29"
|
attrNoStrikethrough = "29"
|
||||||
blackForegroundColorAttr = "30"
|
attrBlackForegroundColor = "30"
|
||||||
redForegroundColorAttr = "31"
|
attrRedForegroundColor = "31"
|
||||||
greenForegroundColorAttr = "32"
|
attrGreenForegroundColor = "32"
|
||||||
yellowForegroundColorAttr = "33"
|
attrYellowForegroundColor = "33"
|
||||||
blueForegroundColorAttr = "34"
|
attrBlueForegroundColor = "34"
|
||||||
magentaForegroundColorAttr = "35"
|
attrMagentaForegroundColor = "35"
|
||||||
cyanForegroundColorAttr = "36"
|
attrCyanForegroundColor = "36"
|
||||||
whiteForegroundColorAttr = "37"
|
attrWhiteForegroundColor = "37"
|
||||||
extendedForegroundColorAttr = "38"
|
attrExtendedForegroundColor = "38"
|
||||||
defaultForegroundColorAttr = "39"
|
attrDefaultForegroundColor = "39"
|
||||||
blackBackgroundColorAttr = "40"
|
attrBlackBackgroundColor = "40"
|
||||||
redBackgroundColorAttr = "41"
|
attrRedBackgroundColor = "41"
|
||||||
greenBackgroundColorAttr = "42"
|
attrGreenBackgroundColor = "42"
|
||||||
yellowBackgroundColorAttr = "43"
|
attrYellowBackgroundColor = "43"
|
||||||
blueBackgroundColorAttr = "44"
|
attrBlueBackgroundColor = "44"
|
||||||
magentaBackgroundColorAttr = "45"
|
attrMagentaBackgroundColor = "45"
|
||||||
cyanBackgroundColorAttr = "46"
|
attrCyanBackgroundColor = "46"
|
||||||
whiteBackgroundColorAttr = "47"
|
attrWhiteBackgroundColor = "47"
|
||||||
extendedBackgroundColorAttr = "48"
|
attrExtendedBackgroundColor = "48"
|
||||||
defaultBackgroundColorAttr = "49"
|
attrDefaultBackgroundColor = "49"
|
||||||
extendedUnderlineColorAttr = "58"
|
attrExtendedUnderlineColor = "58"
|
||||||
defaultUnderlineColorAttr = "59"
|
attrDefaultUnderlineColor = "59"
|
||||||
brightBlackForegroundColorAttr = "90"
|
attrBrightBlackForegroundColor = "90"
|
||||||
brightRedForegroundColorAttr = "91"
|
attrBrightRedForegroundColor = "91"
|
||||||
brightGreenForegroundColorAttr = "92"
|
attrBrightGreenForegroundColor = "92"
|
||||||
brightYellowForegroundColorAttr = "93"
|
attrBrightYellowForegroundColor = "93"
|
||||||
brightBlueForegroundColorAttr = "94"
|
attrBrightBlueForegroundColor = "94"
|
||||||
brightMagentaForegroundColorAttr = "95"
|
attrBrightMagentaForegroundColor = "95"
|
||||||
brightCyanForegroundColorAttr = "96"
|
attrBrightCyanForegroundColor = "96"
|
||||||
brightWhiteForegroundColorAttr = "97"
|
attrBrightWhiteForegroundColor = "97"
|
||||||
brightBlackBackgroundColorAttr = "100"
|
attrBrightBlackBackgroundColor = "100"
|
||||||
brightRedBackgroundColorAttr = "101"
|
attrBrightRedBackgroundColor = "101"
|
||||||
brightGreenBackgroundColorAttr = "102"
|
attrBrightGreenBackgroundColor = "102"
|
||||||
brightYellowBackgroundColorAttr = "103"
|
attrBrightYellowBackgroundColor = "103"
|
||||||
brightBlueBackgroundColorAttr = "104"
|
attrBrightBlueBackgroundColor = "104"
|
||||||
brightMagentaBackgroundColorAttr = "105"
|
attrBrightMagentaBackgroundColor = "105"
|
||||||
brightCyanBackgroundColorAttr = "106"
|
attrBrightCyanBackgroundColor = "106"
|
||||||
brightWhiteBackgroundColorAttr = "107"
|
attrBrightWhiteBackgroundColor = "107"
|
||||||
)
|
)
|
||||||
|
|
||||||
// foregroundColorString returns the style SGR attribute for the given
|
// foregroundColorString returns the style SGR attribute for the given
|
||||||
@ -364,42 +504,44 @@ const (
|
|||||||
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
||||||
func foregroundColorString(c Color) string {
|
func foregroundColorString(c Color) string {
|
||||||
switch c := c.(type) {
|
switch c := c.(type) {
|
||||||
|
case nil:
|
||||||
|
return attrDefaultForegroundColor
|
||||||
case BasicColor:
|
case BasicColor:
|
||||||
// 3-bit or 4-bit ANSI foreground
|
// 3-bit or 4-bit ANSI foreground
|
||||||
// "3<n>" or "9<n>" where n is the color number from 0 to 7
|
// "3<n>" or "9<n>" where n is the color number from 0 to 7
|
||||||
switch c {
|
switch c {
|
||||||
case Black:
|
case Black:
|
||||||
return blackForegroundColorAttr
|
return attrBlackForegroundColor
|
||||||
case Red:
|
case Red:
|
||||||
return redForegroundColorAttr
|
return attrRedForegroundColor
|
||||||
case Green:
|
case Green:
|
||||||
return greenForegroundColorAttr
|
return attrGreenForegroundColor
|
||||||
case Yellow:
|
case Yellow:
|
||||||
return yellowForegroundColorAttr
|
return attrYellowForegroundColor
|
||||||
case Blue:
|
case Blue:
|
||||||
return blueForegroundColorAttr
|
return attrBlueForegroundColor
|
||||||
case Magenta:
|
case Magenta:
|
||||||
return magentaForegroundColorAttr
|
return attrMagentaForegroundColor
|
||||||
case Cyan:
|
case Cyan:
|
||||||
return cyanForegroundColorAttr
|
return attrCyanForegroundColor
|
||||||
case White:
|
case White:
|
||||||
return whiteForegroundColorAttr
|
return attrWhiteForegroundColor
|
||||||
case BrightBlack:
|
case BrightBlack:
|
||||||
return brightBlackForegroundColorAttr
|
return attrBrightBlackForegroundColor
|
||||||
case BrightRed:
|
case BrightRed:
|
||||||
return brightRedForegroundColorAttr
|
return attrBrightRedForegroundColor
|
||||||
case BrightGreen:
|
case BrightGreen:
|
||||||
return brightGreenForegroundColorAttr
|
return attrBrightGreenForegroundColor
|
||||||
case BrightYellow:
|
case BrightYellow:
|
||||||
return brightYellowForegroundColorAttr
|
return attrBrightYellowForegroundColor
|
||||||
case BrightBlue:
|
case BrightBlue:
|
||||||
return brightBlueForegroundColorAttr
|
return attrBrightBlueForegroundColor
|
||||||
case BrightMagenta:
|
case BrightMagenta:
|
||||||
return brightMagentaForegroundColorAttr
|
return attrBrightMagentaForegroundColor
|
||||||
case BrightCyan:
|
case BrightCyan:
|
||||||
return brightCyanForegroundColorAttr
|
return attrBrightCyanForegroundColor
|
||||||
case BrightWhite:
|
case BrightWhite:
|
||||||
return brightWhiteForegroundColorAttr
|
return attrBrightWhiteForegroundColor
|
||||||
}
|
}
|
||||||
case ExtendedColor:
|
case ExtendedColor:
|
||||||
// 256-color ANSI foreground
|
// 256-color ANSI foreground
|
||||||
@ -414,7 +556,7 @@ func foregroundColorString(c Color) string {
|
|||||||
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
||||||
strconv.FormatUint(uint64(shift(b)), 10)
|
strconv.FormatUint(uint64(shift(b)), 10)
|
||||||
}
|
}
|
||||||
return defaultForegroundColorAttr
|
return attrDefaultForegroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
// backgroundColorString returns the style SGR attribute for the given
|
// backgroundColorString returns the style SGR attribute for the given
|
||||||
@ -422,42 +564,44 @@ func foregroundColorString(c Color) string {
|
|||||||
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
||||||
func backgroundColorString(c Color) string {
|
func backgroundColorString(c Color) string {
|
||||||
switch c := c.(type) {
|
switch c := c.(type) {
|
||||||
|
case nil:
|
||||||
|
return attrDefaultBackgroundColor
|
||||||
case BasicColor:
|
case BasicColor:
|
||||||
// 3-bit or 4-bit ANSI foreground
|
// 3-bit or 4-bit ANSI foreground
|
||||||
// "4<n>" or "10<n>" where n is the color number from 0 to 7
|
// "4<n>" or "10<n>" where n is the color number from 0 to 7
|
||||||
switch c {
|
switch c {
|
||||||
case Black:
|
case Black:
|
||||||
return blackBackgroundColorAttr
|
return attrBlackBackgroundColor
|
||||||
case Red:
|
case Red:
|
||||||
return redBackgroundColorAttr
|
return attrRedBackgroundColor
|
||||||
case Green:
|
case Green:
|
||||||
return greenBackgroundColorAttr
|
return attrGreenBackgroundColor
|
||||||
case Yellow:
|
case Yellow:
|
||||||
return yellowBackgroundColorAttr
|
return attrYellowBackgroundColor
|
||||||
case Blue:
|
case Blue:
|
||||||
return blueBackgroundColorAttr
|
return attrBlueBackgroundColor
|
||||||
case Magenta:
|
case Magenta:
|
||||||
return magentaBackgroundColorAttr
|
return attrMagentaBackgroundColor
|
||||||
case Cyan:
|
case Cyan:
|
||||||
return cyanBackgroundColorAttr
|
return attrCyanBackgroundColor
|
||||||
case White:
|
case White:
|
||||||
return whiteBackgroundColorAttr
|
return attrWhiteBackgroundColor
|
||||||
case BrightBlack:
|
case BrightBlack:
|
||||||
return brightBlackBackgroundColorAttr
|
return attrBrightBlackBackgroundColor
|
||||||
case BrightRed:
|
case BrightRed:
|
||||||
return brightRedBackgroundColorAttr
|
return attrBrightRedBackgroundColor
|
||||||
case BrightGreen:
|
case BrightGreen:
|
||||||
return brightGreenBackgroundColorAttr
|
return attrBrightGreenBackgroundColor
|
||||||
case BrightYellow:
|
case BrightYellow:
|
||||||
return brightYellowBackgroundColorAttr
|
return attrBrightYellowBackgroundColor
|
||||||
case BrightBlue:
|
case BrightBlue:
|
||||||
return brightBlueBackgroundColorAttr
|
return attrBrightBlueBackgroundColor
|
||||||
case BrightMagenta:
|
case BrightMagenta:
|
||||||
return brightMagentaBackgroundColorAttr
|
return attrBrightMagentaBackgroundColor
|
||||||
case BrightCyan:
|
case BrightCyan:
|
||||||
return brightCyanBackgroundColorAttr
|
return attrBrightCyanBackgroundColor
|
||||||
case BrightWhite:
|
case BrightWhite:
|
||||||
return brightWhiteBackgroundColorAttr
|
return attrBrightWhiteBackgroundColor
|
||||||
}
|
}
|
||||||
case ExtendedColor:
|
case ExtendedColor:
|
||||||
// 256-color ANSI foreground
|
// 256-color ANSI foreground
|
||||||
@ -472,7 +616,7 @@ func backgroundColorString(c Color) string {
|
|||||||
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
||||||
strconv.FormatUint(uint64(shift(b)), 10)
|
strconv.FormatUint(uint64(shift(b)), 10)
|
||||||
}
|
}
|
||||||
return defaultBackgroundColorAttr
|
return attrDefaultBackgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
// underlineColorString returns the style SGR attribute for the given underline
|
// underlineColorString returns the style SGR attribute for the given underline
|
||||||
@ -480,6 +624,8 @@ func backgroundColorString(c Color) string {
|
|||||||
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
||||||
func underlineColorString(c Color) string {
|
func underlineColorString(c Color) string {
|
||||||
switch c := c.(type) {
|
switch c := c.(type) {
|
||||||
|
case nil:
|
||||||
|
return attrDefaultUnderlineColor
|
||||||
// NOTE: we can't use 3-bit and 4-bit ANSI color codes with underline
|
// NOTE: we can't use 3-bit and 4-bit ANSI color codes with underline
|
||||||
// color, use 256-color instead.
|
// color, use 256-color instead.
|
||||||
//
|
//
|
||||||
@ -498,7 +644,7 @@ func underlineColorString(c Color) string {
|
|||||||
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
||||||
strconv.FormatUint(uint64(shift(b)), 10)
|
strconv.FormatUint(uint64(shift(b)), 10)
|
||||||
}
|
}
|
||||||
return defaultUnderlineColorAttr
|
return attrDefaultUnderlineColor
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadStyleColor decodes a color from a slice of parameters. It returns the
|
// ReadStyleColor decodes a color from a slice of parameters. It returns the
|
||||||
@ -526,7 +672,7 @@ func underlineColorString(c Color) string {
|
|||||||
// 2. Support ignoring and omitting the color space id (second parameter) with respect to RGB colors
|
// 2. Support ignoring and omitting the color space id (second parameter) with respect to RGB colors
|
||||||
// 3. Support ignoring and omitting the 6th parameter with respect to RGB and CMY colors
|
// 3. Support ignoring and omitting the 6th parameter with respect to RGB and CMY colors
|
||||||
// 4. Support reading RGBA colors
|
// 4. Support reading RGBA colors
|
||||||
func ReadStyleColor(params Params, co *color.Color) (n int) {
|
func ReadStyleColor(params Params, co *color.Color) int {
|
||||||
if len(params) < 2 { // Need at least SGR type and color type
|
if len(params) < 2 { // Need at least SGR type and color type
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -535,7 +681,7 @@ func ReadStyleColor(params Params, co *color.Color) (n int) {
|
|||||||
s := params[0]
|
s := params[0]
|
||||||
p := params[1]
|
p := params[1]
|
||||||
colorType := p.Param(0)
|
colorType := p.Param(0)
|
||||||
n = 2
|
n := 2
|
||||||
|
|
||||||
paramsfn := func() (p1, p2, p3, p4 int) {
|
paramsfn := func() (p1, p2, p3, p4 int) {
|
||||||
// Where should we start reading the color?
|
// Where should we start reading the color?
|
||||||
@ -594,7 +740,7 @@ func ReadStyleColor(params Params, co *color.Color) (n int) {
|
|||||||
B: uint8(b), //nolint:gosec
|
B: uint8(b), //nolint:gosec
|
||||||
A: 0xff,
|
A: 0xff,
|
||||||
}
|
}
|
||||||
return //nolint:nakedret
|
return n
|
||||||
|
|
||||||
case 3: // CMY direct color
|
case 3: // CMY direct color
|
||||||
if len(params) < 5 {
|
if len(params) < 5 {
|
||||||
@ -612,7 +758,7 @@ func ReadStyleColor(params Params, co *color.Color) (n int) {
|
|||||||
Y: uint8(y), //nolint:gosec
|
Y: uint8(y), //nolint:gosec
|
||||||
K: 0,
|
K: 0,
|
||||||
}
|
}
|
||||||
return //nolint:nakedret
|
return n
|
||||||
|
|
||||||
case 4: // CMYK direct color
|
case 4: // CMYK direct color
|
||||||
if len(params) < 6 {
|
if len(params) < 6 {
|
||||||
@ -630,7 +776,7 @@ func ReadStyleColor(params Params, co *color.Color) (n int) {
|
|||||||
Y: uint8(y), //nolint:gosec
|
Y: uint8(y), //nolint:gosec
|
||||||
K: uint8(k), //nolint:gosec
|
K: uint8(k), //nolint:gosec
|
||||||
}
|
}
|
||||||
return //nolint:nakedret
|
return n
|
||||||
|
|
||||||
case 5: // indexed color
|
case 5: // indexed color
|
||||||
if len(params) < 3 {
|
if len(params) < 3 {
|
||||||
@ -665,7 +811,7 @@ func ReadStyleColor(params Params, co *color.Color) (n int) {
|
|||||||
B: uint8(b), //nolint:gosec
|
B: uint8(b), //nolint:gosec
|
||||||
A: uint8(a), //nolint:gosec
|
A: uint8(a), //nolint:gosec
|
||||||
}
|
}
|
||||||
return //nolint:nakedret
|
return n
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
57
vendor/github.com/charmbracelet/x/ansi/truncate.go
generated
vendored
57
vendor/github.com/charmbracelet/x/ansi/truncate.go
generated
vendored
@ -1,11 +1,11 @@
|
|||||||
package ansi
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"strings"
|
||||||
|
|
||||||
"github.com/charmbracelet/x/ansi/parser"
|
"github.com/charmbracelet/x/ansi/parser"
|
||||||
"github.com/mattn/go-runewidth"
|
"github.com/clipperhouse/displaywidth"
|
||||||
"github.com/rivo/uniseg"
|
"github.com/clipperhouse/uax29/v2/graphemes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cut the string, without adding any prefix or tail strings. This function is
|
// Cut the string, without adding any prefix or tail strings. This function is
|
||||||
@ -74,12 +74,11 @@ func truncate(m Method, s string, length int, tail string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var cluster []byte
|
var cluster string
|
||||||
var buf bytes.Buffer
|
var buf strings.Builder
|
||||||
curWidth := 0
|
curWidth := 0
|
||||||
ignoring := false
|
ignoring := false
|
||||||
pstate := parser.GroundState // initial state
|
pstate := parser.GroundState // initial state
|
||||||
b := []byte(s)
|
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
// Here we iterate over the bytes of the string and collect printable
|
// Here we iterate over the bytes of the string and collect printable
|
||||||
@ -88,16 +87,12 @@ func truncate(m Method, s string, length int, tail string) string {
|
|||||||
//
|
//
|
||||||
// Once we reach the given length, we start ignoring characters and only
|
// Once we reach the given length, we start ignoring characters and only
|
||||||
// collect ANSI escape codes until we reach the end of string.
|
// collect ANSI escape codes until we reach the end of string.
|
||||||
for i < len(b) {
|
for i < len(s) {
|
||||||
state, action := parser.Table.Transition(pstate, b[i])
|
state, action := parser.Table.Transition(pstate, s[i])
|
||||||
if state == parser.Utf8State {
|
if state == parser.Utf8State {
|
||||||
// This action happens when we transition to the Utf8State.
|
// This action happens when we transition to the Utf8State.
|
||||||
var width int
|
var width int
|
||||||
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
|
cluster, width = FirstGraphemeCluster(s[i:], m)
|
||||||
if m == WcWidth {
|
|
||||||
width = runewidth.StringWidth(string(cluster))
|
|
||||||
}
|
|
||||||
|
|
||||||
// increment the index by the length of the cluster
|
// increment the index by the length of the cluster
|
||||||
i += len(cluster)
|
i += len(cluster)
|
||||||
curWidth += width
|
curWidth += width
|
||||||
@ -118,7 +113,7 @@ func truncate(m Method, s string, length int, tail string) string {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.Write(cluster)
|
buf.WriteString(cluster)
|
||||||
|
|
||||||
// Done collecting, now we're back in the ground state.
|
// Done collecting, now we're back in the ground state.
|
||||||
pstate = parser.GroundState
|
pstate = parser.GroundState
|
||||||
@ -152,7 +147,7 @@ func truncate(m Method, s string, length int, tail string) string {
|
|||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
buf.WriteByte(b[i])
|
buf.WriteByte(s[i])
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,27 +188,23 @@ func truncateLeft(m Method, s string, n int, prefix string) string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
var cluster []byte
|
var cluster string
|
||||||
var buf bytes.Buffer
|
var buf strings.Builder
|
||||||
curWidth := 0
|
curWidth := 0
|
||||||
ignoring := true
|
ignoring := true
|
||||||
pstate := parser.GroundState
|
pstate := parser.GroundState
|
||||||
b := []byte(s)
|
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
for i < len(b) {
|
for i < len(s) {
|
||||||
if !ignoring {
|
if !ignoring {
|
||||||
buf.Write(b[i:])
|
buf.WriteString(s[i:])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
state, action := parser.Table.Transition(pstate, b[i])
|
state, action := parser.Table.Transition(pstate, s[i])
|
||||||
if state == parser.Utf8State {
|
if state == parser.Utf8State {
|
||||||
var width int
|
var width int
|
||||||
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
|
cluster, width = FirstGraphemeCluster(s[i:], m)
|
||||||
if m == WcWidth {
|
|
||||||
width = runewidth.StringWidth(string(cluster))
|
|
||||||
}
|
|
||||||
|
|
||||||
i += len(cluster)
|
i += len(cluster)
|
||||||
curWidth += width
|
curWidth += width
|
||||||
@ -224,7 +215,7 @@ func truncateLeft(m Method, s string, n int, prefix string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if curWidth > n {
|
if curWidth > n {
|
||||||
buf.Write(cluster)
|
buf.WriteString(cluster)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ignoring {
|
if ignoring {
|
||||||
@ -259,7 +250,7 @@ func truncateLeft(m Method, s string, n int, prefix string) string {
|
|||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
buf.WriteByte(b[i])
|
buf.WriteByte(s[i])
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,22 +269,22 @@ func truncateLeft(m Method, s string, n int, prefix string) string {
|
|||||||
// You can use this with [Truncate], [TruncateLeft], and [Cut].
|
// You can use this with [Truncate], [TruncateLeft], and [Cut].
|
||||||
func ByteToGraphemeRange(str string, byteStart, byteStop int) (charStart, charStop int) {
|
func ByteToGraphemeRange(str string, byteStart, byteStop int) (charStart, charStop int) {
|
||||||
bytePos, charPos := 0, 0
|
bytePos, charPos := 0, 0
|
||||||
gr := uniseg.NewGraphemes(str)
|
gr := graphemes.FromString(str)
|
||||||
for byteStart > bytePos {
|
for byteStart > bytePos {
|
||||||
if !gr.Next() {
|
if !gr.Next() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
bytePos += len(gr.Str())
|
bytePos += len(gr.Value())
|
||||||
charPos += max(1, gr.Width())
|
charPos += max(1, displaywidth.String(gr.Value()))
|
||||||
}
|
}
|
||||||
charStart = charPos
|
charStart = charPos
|
||||||
for byteStop > bytePos {
|
for byteStop > bytePos {
|
||||||
if !gr.Next() {
|
if !gr.Next() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
bytePos += len(gr.Str())
|
bytePos += len(gr.Value())
|
||||||
charPos += max(1, gr.Width())
|
charPos += max(1, displaywidth.String(gr.Value()))
|
||||||
}
|
}
|
||||||
charStop = charPos
|
charStop = charPos
|
||||||
return
|
return charStart, charStop
|
||||||
}
|
}
|
||||||
|
|||||||
17
vendor/github.com/charmbracelet/x/ansi/urxvt.go
generated
vendored
Normal file
17
vendor/github.com/charmbracelet/x/ansi/urxvt.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// URxvtExt returns an escape sequence for calling a URxvt perl extension with
|
||||||
|
// the given name and parameters.
|
||||||
|
//
|
||||||
|
// OSC 777 ; extension_name ; param1 ; param2 ; ... ST
|
||||||
|
// OSC 777 ; extension_name ; param1 ; param2 ; ... BEL
|
||||||
|
//
|
||||||
|
// See: https://man.archlinux.org/man/extra/rxvt-unicode/urxvt.7.en#XTerm_Operating_System_Commands
|
||||||
|
func URxvtExt(extension string, params ...string) string {
|
||||||
|
return fmt.Sprintf("\x1b]777;%s;%s\x07", extension, strings.Join(params, ";"))
|
||||||
|
}
|
||||||
14
vendor/github.com/charmbracelet/x/ansi/width.go
generated
vendored
14
vendor/github.com/charmbracelet/x/ansi/width.go
generated
vendored
@ -4,8 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
"github.com/charmbracelet/x/ansi/parser"
|
"github.com/charmbracelet/x/ansi/parser"
|
||||||
"github.com/mattn/go-runewidth"
|
|
||||||
"github.com/rivo/uniseg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Strip removes ANSI escape codes from a string.
|
// Strip removes ANSI escape codes from a string.
|
||||||
@ -83,20 +81,16 @@ func stringWidth(m Method, s string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
pstate = parser.GroundState // initial state
|
pstate = parser.GroundState // initial state
|
||||||
cluster string
|
width int
|
||||||
width int
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
state, action := parser.Table.Transition(pstate, s[i])
|
state, action := parser.Table.Transition(pstate, s[i])
|
||||||
if state == parser.Utf8State {
|
if state == parser.Utf8State {
|
||||||
var w int
|
cluster, w := FirstGraphemeCluster(s[i:], m)
|
||||||
cluster, _, w, _ = uniseg.FirstGraphemeClusterInString(s[i:], -1)
|
|
||||||
if m == WcWidth {
|
|
||||||
w = runewidth.StringWidth(cluster)
|
|
||||||
}
|
|
||||||
width += w
|
width += w
|
||||||
|
|
||||||
i += len(cluster) - 1
|
i += len(cluster) - 1
|
||||||
pstate = parser.GroundState
|
pstate = parser.GroundState
|
||||||
continue
|
continue
|
||||||
|
|||||||
50
vendor/github.com/charmbracelet/x/ansi/wrap.go
generated
vendored
50
vendor/github.com/charmbracelet/x/ansi/wrap.go
generated
vendored
@ -2,12 +2,11 @@ package ansi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/charmbracelet/x/ansi/parser"
|
"github.com/charmbracelet/x/ansi/parser"
|
||||||
"github.com/mattn/go-runewidth"
|
|
||||||
"github.com/rivo/uniseg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// nbsp is a non-breaking space.
|
// nbsp is a non-breaking space.
|
||||||
@ -55,12 +54,9 @@ func hardwrap(m Method, s string, limit int, preserveSpace bool) string {
|
|||||||
i := 0
|
i := 0
|
||||||
for i < len(b) {
|
for i < len(b) {
|
||||||
state, action := parser.Table.Transition(pstate, b[i])
|
state, action := parser.Table.Transition(pstate, b[i])
|
||||||
if state == parser.Utf8State { //nolint:nestif
|
if state == parser.Utf8State {
|
||||||
var width int
|
var width int
|
||||||
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
|
cluster, width = FirstGraphemeCluster(b[i:], m)
|
||||||
if m == WcWidth {
|
|
||||||
width = runewidth.StringWidth(string(cluster))
|
|
||||||
}
|
|
||||||
i += len(cluster)
|
i += len(cluster)
|
||||||
|
|
||||||
if curWidth+width > limit {
|
if curWidth+width > limit {
|
||||||
@ -192,10 +188,7 @@ func wordwrap(m Method, s string, limit int, breakpoints string) string {
|
|||||||
state, action := parser.Table.Transition(pstate, b[i])
|
state, action := parser.Table.Transition(pstate, b[i])
|
||||||
if state == parser.Utf8State { //nolint:nestif
|
if state == parser.Utf8State { //nolint:nestif
|
||||||
var width int
|
var width int
|
||||||
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
|
cluster, width = FirstGraphemeCluster(b[i:], m)
|
||||||
if m == WcWidth {
|
|
||||||
width = runewidth.StringWidth(string(cluster))
|
|
||||||
}
|
|
||||||
i += len(cluster)
|
i += len(cluster)
|
||||||
|
|
||||||
r, _ := utf8.DecodeRune(cluster)
|
r, _ := utf8.DecodeRune(cluster)
|
||||||
@ -303,7 +296,7 @@ func wrap(m Method, s string, limit int, breakpoints string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cluster []byte
|
cluster string
|
||||||
buf bytes.Buffer
|
buf bytes.Buffer
|
||||||
word bytes.Buffer
|
word bytes.Buffer
|
||||||
space bytes.Buffer
|
space bytes.Buffer
|
||||||
@ -311,10 +304,12 @@ func wrap(m Method, s string, limit int, breakpoints string) string {
|
|||||||
curWidth int // written width of the line
|
curWidth int // written width of the line
|
||||||
wordLen int // word buffer len without ANSI escape codes
|
wordLen int // word buffer len without ANSI escape codes
|
||||||
pstate = parser.GroundState // initial state
|
pstate = parser.GroundState // initial state
|
||||||
b = []byte(s)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
addSpace := func() {
|
addSpace := func() {
|
||||||
|
if spaceWidth == 0 && space.Len() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
curWidth += spaceWidth
|
curWidth += spaceWidth
|
||||||
buf.Write(space.Bytes())
|
buf.Write(space.Bytes())
|
||||||
space.Reset()
|
space.Reset()
|
||||||
@ -341,30 +336,27 @@ func wrap(m Method, s string, limit int, breakpoints string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for i < len(b) {
|
for i < len(s) {
|
||||||
state, action := parser.Table.Transition(pstate, b[i])
|
state, action := parser.Table.Transition(pstate, s[i])
|
||||||
if state == parser.Utf8State { //nolint:nestif
|
if state == parser.Utf8State { //nolint:nestif
|
||||||
var width int
|
var width int
|
||||||
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
|
cluster, width = FirstGraphemeCluster(s[i:], m)
|
||||||
if m == WcWidth {
|
|
||||||
width = runewidth.StringWidth(string(cluster))
|
|
||||||
}
|
|
||||||
i += len(cluster)
|
i += len(cluster)
|
||||||
|
|
||||||
r, _ := utf8.DecodeRune(cluster)
|
r, _ := utf8.DecodeRuneInString(cluster)
|
||||||
switch {
|
switch {
|
||||||
case r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp: // nbsp is a non-breaking space
|
case r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp: // nbsp is a non-breaking space
|
||||||
addWord()
|
addWord()
|
||||||
space.WriteRune(r)
|
space.WriteRune(r)
|
||||||
spaceWidth += width
|
spaceWidth += width
|
||||||
case bytes.ContainsAny(cluster, breakpoints):
|
case strings.ContainsAny(cluster, breakpoints):
|
||||||
addSpace()
|
addSpace()
|
||||||
if curWidth+wordLen+width > limit {
|
if curWidth+wordLen+width > limit {
|
||||||
word.Write(cluster)
|
word.WriteString(cluster)
|
||||||
wordLen += width
|
wordLen += width
|
||||||
} else {
|
} else {
|
||||||
addWord()
|
addWord()
|
||||||
buf.Write(cluster)
|
buf.WriteString(cluster)
|
||||||
curWidth += width
|
curWidth += width
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -373,12 +365,17 @@ func wrap(m Method, s string, limit int, breakpoints string) string {
|
|||||||
addWord()
|
addWord()
|
||||||
}
|
}
|
||||||
|
|
||||||
word.Write(cluster)
|
word.WriteString(cluster)
|
||||||
wordLen += width
|
wordLen += width
|
||||||
|
|
||||||
if curWidth+wordLen+spaceWidth > limit {
|
if curWidth+wordLen+spaceWidth > limit {
|
||||||
addNewline()
|
addNewline()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if wordLen == limit {
|
||||||
|
// Hardwrap the word if it's too long
|
||||||
|
addWord()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pstate = parser.GroundState
|
pstate = parser.GroundState
|
||||||
@ -387,7 +384,7 @@ func wrap(m Method, s string, limit int, breakpoints string) string {
|
|||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case parser.PrintAction, parser.ExecuteAction:
|
case parser.PrintAction, parser.ExecuteAction:
|
||||||
switch r := rune(b[i]); {
|
switch r := rune(s[i]); {
|
||||||
case r == '\n':
|
case r == '\n':
|
||||||
if wordLen == 0 {
|
if wordLen == 0 {
|
||||||
if curWidth+spaceWidth > limit {
|
if curWidth+spaceWidth > limit {
|
||||||
@ -424,6 +421,7 @@ func wrap(m Method, s string, limit int, breakpoints string) string {
|
|||||||
if curWidth == limit {
|
if curWidth == limit {
|
||||||
addNewline()
|
addNewline()
|
||||||
}
|
}
|
||||||
|
|
||||||
word.WriteRune(r)
|
word.WriteRune(r)
|
||||||
wordLen++
|
wordLen++
|
||||||
|
|
||||||
@ -438,7 +436,7 @@ func wrap(m Method, s string, limit int, breakpoints string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
word.WriteByte(b[i])
|
word.WriteByte(s[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// We manage the UTF8 state separately manually above.
|
// We manage the UTF8 state separately manually above.
|
||||||
|
|||||||
15
vendor/github.com/charmbracelet/x/cellbuf/buffer.go
generated
vendored
15
vendor/github.com/charmbracelet/x/cellbuf/buffer.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
// Package cellbuf provides terminal cell buffer functionality.
|
||||||
package cellbuf
|
package cellbuf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -24,7 +25,7 @@ func NewCell(r rune, comb ...rune) (c *Cell) {
|
|||||||
}
|
}
|
||||||
c.Comb = comb
|
c.Comb = comb
|
||||||
c.Width = runewidth.StringWidth(string(append([]rune{r}, comb...)))
|
c.Width = runewidth.StringWidth(string(append([]rune{r}, comb...)))
|
||||||
return
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCellString returns a new cell with the given string content. This is a
|
// NewCellString returns a new cell with the given string content. This is a
|
||||||
@ -46,7 +47,7 @@ func NewCellString(s string) (c *Cell) {
|
|||||||
c.Comb = append(c.Comb, r)
|
c.Comb = append(c.Comb, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGraphemeCell returns a new cell. This is a convenience function that
|
// NewGraphemeCell returns a new cell. This is a convenience function that
|
||||||
@ -71,7 +72,7 @@ func newGraphemeCell(s string, w int) (c *Cell) {
|
|||||||
c.Comb = append(c.Comb, r)
|
c.Comb = append(c.Comb, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line represents a line in the terminal.
|
// Line represents a line in the terminal.
|
||||||
@ -104,7 +105,7 @@ func (l Line) String() (s string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = strings.TrimRight(s, " ")
|
s = strings.TrimRight(s, " ")
|
||||||
return
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// At returns the cell at the given x position.
|
// At returns the cell at the given x position.
|
||||||
@ -150,7 +151,7 @@ func (l Line) set(x int, c *Cell, clone bool) bool {
|
|||||||
for j := 1; j < maxCellWidth && x-j >= 0; j++ {
|
for j := 1; j < maxCellWidth && x-j >= 0; j++ {
|
||||||
wide := l.At(x - j)
|
wide := l.At(x - j)
|
||||||
if wide != nil && wide.Width > 1 && j < wide.Width {
|
if wide != nil && wide.Width > 1 && j < wide.Width {
|
||||||
for k := 0; k < wide.Width; k++ {
|
for k := range wide.Width {
|
||||||
l[x-j+k] = wide.Clone().Blank()
|
l[x-j+k] = wide.Clone().Blank()
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -206,7 +207,7 @@ func (b *Buffer) String() (s string) {
|
|||||||
s += "\r\n"
|
s += "\r\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line returns a pointer to the line at the given y position.
|
// Line returns a pointer to the line at the given y position.
|
||||||
@ -296,7 +297,7 @@ func (b *Buffer) FillRect(c *Cell, rect Rectangle) {
|
|||||||
}
|
}
|
||||||
for y := rect.Min.Y; y < rect.Max.Y; y++ {
|
for y := rect.Min.Y; y < rect.Max.Y; y++ {
|
||||||
for x := rect.Min.X; x < rect.Max.X; x += cellWidth {
|
for x := rect.Min.X; x < rect.Max.X; x += cellWidth {
|
||||||
b.setCell(x, y, c, false) //nolint:errcheck
|
b.setCell(x, y, c, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
vendor/github.com/charmbracelet/x/cellbuf/cell.go
generated
vendored
83
vendor/github.com/charmbracelet/x/cellbuf/cell.go
generated
vendored
@ -96,7 +96,7 @@ func (c *Cell) Clear() bool {
|
|||||||
func (c *Cell) Clone() (n *Cell) {
|
func (c *Cell) Clone() (n *Cell) {
|
||||||
n = new(Cell)
|
n = new(Cell)
|
||||||
*n = *c
|
*n = *c
|
||||||
return
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blank makes the cell a blank cell by setting the rune to a space, comb to
|
// Blank makes the cell a blank cell by setting the rune to a space, comb to
|
||||||
@ -164,12 +164,12 @@ type UnderlineStyle = ansi.UnderlineStyle
|
|||||||
|
|
||||||
// These are the available underline styles.
|
// These are the available underline styles.
|
||||||
const (
|
const (
|
||||||
NoUnderline = ansi.NoUnderlineStyle
|
NoUnderline = ansi.UnderlineStyleNone
|
||||||
SingleUnderline = ansi.SingleUnderlineStyle
|
SingleUnderline = ansi.UnderlineStyleSingle
|
||||||
DoubleUnderline = ansi.DoubleUnderlineStyle
|
DoubleUnderline = ansi.UnderlineStyleDouble
|
||||||
CurlyUnderline = ansi.CurlyUnderlineStyle
|
CurlyUnderline = ansi.UnderlineStyleCurly
|
||||||
DottedUnderline = ansi.DottedUnderlineStyle
|
DottedUnderline = ansi.UnderlineStyleDotted
|
||||||
DashedUnderline = ansi.DashedUnderlineStyle
|
DashedUnderline = ansi.UnderlineStyleDashed
|
||||||
)
|
)
|
||||||
|
|
||||||
// Style represents the Style of a cell.
|
// Style represents the Style of a cell.
|
||||||
@ -189,7 +189,7 @@ func (s Style) Sequence() string {
|
|||||||
|
|
||||||
var b ansi.Style
|
var b ansi.Style
|
||||||
|
|
||||||
if s.Attrs != 0 {
|
if s.Attrs != 0 { //nolint:nestif
|
||||||
if s.Attrs&BoldAttr != 0 {
|
if s.Attrs&BoldAttr != 0 {
|
||||||
b = b.Bold()
|
b = b.Bold()
|
||||||
}
|
}
|
||||||
@ -197,36 +197,31 @@ func (s Style) Sequence() string {
|
|||||||
b = b.Faint()
|
b = b.Faint()
|
||||||
}
|
}
|
||||||
if s.Attrs&ItalicAttr != 0 {
|
if s.Attrs&ItalicAttr != 0 {
|
||||||
b = b.Italic()
|
b = b.Italic(true)
|
||||||
}
|
}
|
||||||
if s.Attrs&SlowBlinkAttr != 0 {
|
if s.Attrs&SlowBlinkAttr != 0 {
|
||||||
b = b.SlowBlink()
|
b = b.Blink(true)
|
||||||
}
|
}
|
||||||
if s.Attrs&RapidBlinkAttr != 0 {
|
if s.Attrs&RapidBlinkAttr != 0 {
|
||||||
b = b.RapidBlink()
|
b = b.RapidBlink(true)
|
||||||
}
|
}
|
||||||
if s.Attrs&ReverseAttr != 0 {
|
if s.Attrs&ReverseAttr != 0 {
|
||||||
b = b.Reverse()
|
b = b.Reverse(true)
|
||||||
}
|
}
|
||||||
if s.Attrs&ConcealAttr != 0 {
|
if s.Attrs&ConcealAttr != 0 {
|
||||||
b = b.Conceal()
|
b = b.Conceal(true)
|
||||||
}
|
}
|
||||||
if s.Attrs&StrikethroughAttr != 0 {
|
if s.Attrs&StrikethroughAttr != 0 {
|
||||||
b = b.Strikethrough()
|
b = b.Strikethrough(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.UlStyle != NoUnderline {
|
if s.UlStyle != NoUnderline {
|
||||||
switch s.UlStyle {
|
switch u := s.UlStyle; u {
|
||||||
case SingleUnderline:
|
case NoUnderline:
|
||||||
b = b.Underline()
|
b = b.Underline(false)
|
||||||
case DoubleUnderline:
|
default:
|
||||||
b = b.DoubleUnderline()
|
b = b.Underline(true)
|
||||||
case CurlyUnderline:
|
b = b.UnderlineStyle(u)
|
||||||
b = b.CurlyUnderline()
|
|
||||||
case DottedUnderline:
|
|
||||||
b = b.DottedUnderline()
|
|
||||||
case DashedUnderline:
|
|
||||||
b = b.DashedUnderline()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.Fg != nil {
|
if s.Fg != nil {
|
||||||
@ -268,64 +263,48 @@ func (s Style) DiffSequence(o Style) string {
|
|||||||
isNormal bool
|
isNormal bool
|
||||||
)
|
)
|
||||||
|
|
||||||
if s.Attrs != o.Attrs {
|
if s.Attrs != o.Attrs { //nolint:nestif
|
||||||
if s.Attrs&BoldAttr != o.Attrs&BoldAttr {
|
if s.Attrs&BoldAttr != o.Attrs&BoldAttr {
|
||||||
if s.Attrs&BoldAttr != 0 {
|
if s.Attrs&BoldAttr != 0 {
|
||||||
b = b.Bold()
|
b = b.Bold()
|
||||||
} else if !isNormal {
|
} else if !isNormal {
|
||||||
isNormal = true
|
isNormal = true
|
||||||
b = b.NormalIntensity()
|
b = b.Normal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.Attrs&FaintAttr != o.Attrs&FaintAttr {
|
if s.Attrs&FaintAttr != o.Attrs&FaintAttr {
|
||||||
if s.Attrs&FaintAttr != 0 {
|
if s.Attrs&FaintAttr != 0 {
|
||||||
b = b.Faint()
|
b = b.Faint()
|
||||||
} else if !isNormal {
|
} else if !isNormal {
|
||||||
b = b.NormalIntensity()
|
b = b.Normal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.Attrs&ItalicAttr != o.Attrs&ItalicAttr {
|
if s.Attrs&ItalicAttr != o.Attrs&ItalicAttr {
|
||||||
if s.Attrs&ItalicAttr != 0 {
|
b = b.Italic(s.Attrs&ItalicAttr != 0)
|
||||||
b = b.Italic()
|
|
||||||
} else {
|
|
||||||
b = b.NoItalic()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if s.Attrs&SlowBlinkAttr != o.Attrs&SlowBlinkAttr {
|
if s.Attrs&SlowBlinkAttr != o.Attrs&SlowBlinkAttr {
|
||||||
if s.Attrs&SlowBlinkAttr != 0 {
|
if s.Attrs&SlowBlinkAttr != 0 {
|
||||||
b = b.SlowBlink()
|
b = b.Blink(true)
|
||||||
} else if !noBlink {
|
} else if !noBlink {
|
||||||
noBlink = true
|
noBlink = true
|
||||||
b = b.NoBlink()
|
b = b.Blink(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.Attrs&RapidBlinkAttr != o.Attrs&RapidBlinkAttr {
|
if s.Attrs&RapidBlinkAttr != o.Attrs&RapidBlinkAttr {
|
||||||
if s.Attrs&RapidBlinkAttr != 0 {
|
if s.Attrs&RapidBlinkAttr != 0 {
|
||||||
b = b.RapidBlink()
|
b = b.RapidBlink(true)
|
||||||
} else if !noBlink {
|
} else if !noBlink {
|
||||||
b = b.NoBlink()
|
b = b.Blink(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.Attrs&ReverseAttr != o.Attrs&ReverseAttr {
|
if s.Attrs&ReverseAttr != o.Attrs&ReverseAttr {
|
||||||
if s.Attrs&ReverseAttr != 0 {
|
b = b.Reverse(s.Attrs&ReverseAttr != 0)
|
||||||
b = b.Reverse()
|
|
||||||
} else {
|
|
||||||
b = b.NoReverse()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if s.Attrs&ConcealAttr != o.Attrs&ConcealAttr {
|
if s.Attrs&ConcealAttr != o.Attrs&ConcealAttr {
|
||||||
if s.Attrs&ConcealAttr != 0 {
|
b = b.Conceal(s.Attrs&ConcealAttr != 0)
|
||||||
b = b.Conceal()
|
|
||||||
} else {
|
|
||||||
b = b.NoConceal()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if s.Attrs&StrikethroughAttr != o.Attrs&StrikethroughAttr {
|
if s.Attrs&StrikethroughAttr != o.Attrs&StrikethroughAttr {
|
||||||
if s.Attrs&StrikethroughAttr != 0 {
|
b = b.Strikethrough(s.Attrs&StrikethroughAttr != 0)
|
||||||
b = b.Strikethrough()
|
|
||||||
} else {
|
|
||||||
b = b.NoStrikethrough()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
vendor/github.com/charmbracelet/x/cellbuf/geom.go
generated
vendored
2
vendor/github.com/charmbracelet/x/cellbuf/geom.go
generated
vendored
@ -12,7 +12,7 @@ func Pos(x, y int) Position {
|
|||||||
return image.Pt(x, y)
|
return image.Pt(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rectange represents a rectangle.
|
// Rectangle represents a rectangle.
|
||||||
type Rectangle = image.Rectangle
|
type Rectangle = image.Rectangle
|
||||||
|
|
||||||
// Rect is a shorthand for Rectangle.
|
// Rect is a shorthand for Rectangle.
|
||||||
|
|||||||
19
vendor/github.com/charmbracelet/x/cellbuf/hardscroll.go
generated
vendored
19
vendor/github.com/charmbracelet/x/cellbuf/hardscroll.go
generated
vendored
@ -75,7 +75,7 @@ func (s *Screen) scrolln(n, top, bot, maxY int) (v bool) { //nolint:unparam
|
|||||||
)
|
)
|
||||||
|
|
||||||
blank := s.clearBlank()
|
blank := s.clearBlank()
|
||||||
if n > 0 {
|
if n > 0 { //nolint:nestif
|
||||||
// Scroll up (forward)
|
// Scroll up (forward)
|
||||||
v = s.scrollUp(n, top, bot, 0, maxY, blank)
|
v = s.scrollUp(n, top, bot, 0, maxY, blank)
|
||||||
if !v {
|
if !v {
|
||||||
@ -99,7 +99,7 @@ func (s *Screen) scrolln(n, top, bot, maxY int) (v bool) { //nolint:unparam
|
|||||||
s.move(0, bot-n+1)
|
s.move(0, bot-n+1)
|
||||||
s.clearToBottom(nil)
|
s.clearToBottom(nil)
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < n; i++ {
|
for i := range n {
|
||||||
s.move(0, bot-i)
|
s.move(0, bot-i)
|
||||||
s.clearToEnd(nil, false)
|
s.clearToEnd(nil, false)
|
||||||
}
|
}
|
||||||
@ -124,7 +124,7 @@ func (s *Screen) scrolln(n, top, bot, maxY int) (v bool) { //nolint:unparam
|
|||||||
// Clear newly shifted-in lines.
|
// Clear newly shifted-in lines.
|
||||||
if v &&
|
if v &&
|
||||||
(nonDestScrollRegion || (memoryBelow && top == 0)) {
|
(nonDestScrollRegion || (memoryBelow && top == 0)) {
|
||||||
for i := 0; i < -n; i++ {
|
for i := range -n {
|
||||||
s.move(0, top+i)
|
s.move(0, top+i)
|
||||||
s.clearToEnd(nil, false)
|
s.clearToEnd(nil, false)
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ func (s *Screen) scrolln(n, top, bot, maxY int) (v bool) { //nolint:unparam
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !v {
|
if !v {
|
||||||
return
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
s.scrollBuffer(s.curbuf, n, top, bot, blank)
|
s.scrollBuffer(s.curbuf, n, top, bot, blank)
|
||||||
@ -193,7 +193,7 @@ func (s *Screen) touchLine(width, height, y, n int, changed bool) {
|
|||||||
|
|
||||||
// scrollUp scrolls the screen up by n lines.
|
// scrollUp scrolls the screen up by n lines.
|
||||||
func (s *Screen) scrollUp(n, top, bot, minY, maxY int, blank *Cell) bool {
|
func (s *Screen) scrollUp(n, top, bot, minY, maxY int, blank *Cell) bool {
|
||||||
if n == 1 && top == minY && bot == maxY {
|
if n == 1 && top == minY && bot == maxY { //nolint:nestif
|
||||||
s.move(0, bot)
|
s.move(0, bot)
|
||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
s.buf.WriteByte('\n')
|
s.buf.WriteByte('\n')
|
||||||
@ -202,13 +202,14 @@ func (s *Screen) scrollUp(n, top, bot, minY, maxY int, blank *Cell) bool {
|
|||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
s.buf.WriteString(ansi.DeleteLine(1))
|
s.buf.WriteString(ansi.DeleteLine(1))
|
||||||
} else if top == minY && bot == maxY {
|
} else if top == minY && bot == maxY {
|
||||||
if s.xtermLike {
|
supportsSU := s.caps.Contains(capSU)
|
||||||
|
if supportsSU {
|
||||||
s.move(0, bot)
|
s.move(0, bot)
|
||||||
} else {
|
} else {
|
||||||
s.move(0, top)
|
s.move(0, top)
|
||||||
}
|
}
|
||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
if s.xtermLike {
|
if supportsSU {
|
||||||
s.buf.WriteString(ansi.ScrollUp(n))
|
s.buf.WriteString(ansi.ScrollUp(n))
|
||||||
} else {
|
} else {
|
||||||
s.buf.WriteString(strings.Repeat("\n", n))
|
s.buf.WriteString(strings.Repeat("\n", n))
|
||||||
@ -225,7 +226,7 @@ func (s *Screen) scrollUp(n, top, bot, minY, maxY int, blank *Cell) bool {
|
|||||||
|
|
||||||
// scrollDown scrolls the screen down by n lines.
|
// scrollDown scrolls the screen down by n lines.
|
||||||
func (s *Screen) scrollDown(n, top, bot, minY, maxY int, blank *Cell) bool {
|
func (s *Screen) scrollDown(n, top, bot, minY, maxY int, blank *Cell) bool {
|
||||||
if n == 1 && top == minY && bot == maxY {
|
if n == 1 && top == minY && bot == maxY { //nolint:nestif
|
||||||
s.move(0, top)
|
s.move(0, top)
|
||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
s.buf.WriteString(ansi.ReverseIndex)
|
s.buf.WriteString(ansi.ReverseIndex)
|
||||||
@ -236,7 +237,7 @@ func (s *Screen) scrollDown(n, top, bot, minY, maxY int, blank *Cell) bool {
|
|||||||
} else if top == minY && bot == maxY {
|
} else if top == minY && bot == maxY {
|
||||||
s.move(0, top)
|
s.move(0, top)
|
||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
if s.xtermLike {
|
if s.caps.Contains(capSD) {
|
||||||
s.buf.WriteString(ansi.ScrollDown(n))
|
s.buf.WriteString(ansi.ScrollDown(n))
|
||||||
} else {
|
} else {
|
||||||
s.buf.WriteString(strings.Repeat(ansi.ReverseIndex, n))
|
s.buf.WriteString(strings.Repeat(ansi.ReverseIndex, n))
|
||||||
|
|||||||
16
vendor/github.com/charmbracelet/x/cellbuf/hashmap.go
generated
vendored
16
vendor/github.com/charmbracelet/x/cellbuf/hashmap.go
generated
vendored
@ -15,7 +15,7 @@ func hash(l Line) (h uint64) {
|
|||||||
}
|
}
|
||||||
h += (h << 5) + uint64(r)
|
h += (h << 5) + uint64(r)
|
||||||
}
|
}
|
||||||
return
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// hashmap represents a single [Line] hash.
|
// hashmap represents a single [Line] hash.
|
||||||
@ -33,7 +33,7 @@ func (s *Screen) updateHashmap() {
|
|||||||
height := s.newbuf.Height()
|
height := s.newbuf.Height()
|
||||||
if len(s.oldhash) >= height && len(s.newhash) >= height {
|
if len(s.oldhash) >= height && len(s.newhash) >= height {
|
||||||
// rehash changed lines
|
// rehash changed lines
|
||||||
for i := 0; i < height; i++ {
|
for i := range height {
|
||||||
_, ok := s.touch[i]
|
_, ok := s.touch[i]
|
||||||
if ok {
|
if ok {
|
||||||
s.oldhash[i] = hash(s.curbuf.Line(i))
|
s.oldhash[i] = hash(s.curbuf.Line(i))
|
||||||
@ -48,14 +48,14 @@ func (s *Screen) updateHashmap() {
|
|||||||
if len(s.newhash) != height {
|
if len(s.newhash) != height {
|
||||||
s.newhash = make([]uint64, height)
|
s.newhash = make([]uint64, height)
|
||||||
}
|
}
|
||||||
for i := 0; i < height; i++ {
|
for i := range height {
|
||||||
s.oldhash[i] = hash(s.curbuf.Line(i))
|
s.oldhash[i] = hash(s.curbuf.Line(i))
|
||||||
s.newhash[i] = hash(s.newbuf.Line(i))
|
s.newhash[i] = hash(s.newbuf.Line(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.hashtab = make([]hashmap, height*2)
|
s.hashtab = make([]hashmap, height*2)
|
||||||
for i := 0; i < height; i++ {
|
for i := range height {
|
||||||
hashval := s.oldhash[i]
|
hashval := s.oldhash[i]
|
||||||
|
|
||||||
// Find matching hash or empty slot
|
// Find matching hash or empty slot
|
||||||
@ -71,7 +71,7 @@ func (s *Screen) updateHashmap() {
|
|||||||
s.hashtab[idx].oldcount++
|
s.hashtab[idx].oldcount++
|
||||||
s.hashtab[idx].oldindex = i
|
s.hashtab[idx].oldindex = i
|
||||||
}
|
}
|
||||||
for i := 0; i < height; i++ {
|
for i := range height {
|
||||||
hashval := s.newhash[i]
|
hashval := s.newhash[i]
|
||||||
|
|
||||||
// Find matching hash or empty slot
|
// Find matching hash or empty slot
|
||||||
@ -130,7 +130,7 @@ func (s *Screen) updateHashmap() {
|
|||||||
s.growHunks()
|
s.growHunks()
|
||||||
}
|
}
|
||||||
|
|
||||||
// scrollOldhash
|
// scrollOldhash.
|
||||||
func (s *Screen) scrollOldhash(n, top, bot int) {
|
func (s *Screen) scrollOldhash(n, top, bot int) {
|
||||||
if len(s.oldhash) == 0 {
|
if len(s.oldhash) == 0 {
|
||||||
return
|
return
|
||||||
@ -287,7 +287,7 @@ func (s *Screen) updateCost(from, to Line) (cost int) {
|
|||||||
cost++
|
cost++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return cost
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Screen) updateCostBlank(to Line) (cost int) {
|
func (s *Screen) updateCostBlank(to Line) (cost int) {
|
||||||
@ -297,5 +297,5 @@ func (s *Screen) updateCostBlank(to Line) (cost int) {
|
|||||||
cost++
|
cost++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return cost
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/charmbracelet/x/cellbuf/link.go
generated
vendored
2
vendor/github.com/charmbracelet/x/cellbuf/link.go
generated
vendored
@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/charmbracelet/colorprofile"
|
"github.com/charmbracelet/colorprofile"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Convert converts a hyperlink to respect the given color profile.
|
// ConvertLink converts a hyperlink to respect the given color profile.
|
||||||
func ConvertLink(h Link, p colorprofile.Profile) Link {
|
func ConvertLink(h Link, p colorprofile.Profile) Link {
|
||||||
if p == colorprofile.NoTTY {
|
if p == colorprofile.NoTTY {
|
||||||
return Link{}
|
return Link{}
|
||||||
|
|||||||
92
vendor/github.com/charmbracelet/x/cellbuf/pen.go
generated
vendored
Normal file
92
vendor/github.com/charmbracelet/x/cellbuf/pen.go
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package cellbuf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/x/ansi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PenWriter is a writer that writes to a buffer and keeps track of the current
|
||||||
|
// pen style and link state for the purpose of wrapping with newlines.
|
||||||
|
type PenWriter struct {
|
||||||
|
w io.Writer
|
||||||
|
p *ansi.Parser
|
||||||
|
style Style
|
||||||
|
link Link
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPenWriter returns a new PenWriter.
|
||||||
|
func NewPenWriter(w io.Writer) *PenWriter {
|
||||||
|
pw := &PenWriter{w: w}
|
||||||
|
pw.p = ansi.GetParser()
|
||||||
|
handleCsi := func(cmd ansi.Cmd, params ansi.Params) {
|
||||||
|
if cmd == 'm' {
|
||||||
|
ReadStyle(params, &pw.style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleOsc := func(cmd int, data []byte) {
|
||||||
|
if cmd == 8 {
|
||||||
|
ReadLink(data, &pw.link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pw.p.SetHandler(ansi.Handler{
|
||||||
|
HandleCsi: handleCsi,
|
||||||
|
HandleOsc: handleOsc,
|
||||||
|
})
|
||||||
|
return pw
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style returns the current pen style.
|
||||||
|
func (w *PenWriter) Style() Style {
|
||||||
|
return w.style
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link returns the current pen link.
|
||||||
|
func (w *PenWriter) Link() Link {
|
||||||
|
return w.link
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes to the buffer.
|
||||||
|
func (w *PenWriter) Write(p []byte) (int, error) {
|
||||||
|
for i := range p {
|
||||||
|
b := p[i]
|
||||||
|
w.p.Advance(b)
|
||||||
|
if b == '\n' {
|
||||||
|
if !w.style.Empty() {
|
||||||
|
_, _ = w.w.Write([]byte(ansi.ResetStyle))
|
||||||
|
}
|
||||||
|
if !w.link.Empty() {
|
||||||
|
_, _ = w.w.Write([]byte(ansi.ResetHyperlink()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _ = w.w.Write([]byte{b})
|
||||||
|
if b == '\n' {
|
||||||
|
if !w.link.Empty() {
|
||||||
|
_, _ = w.w.Write([]byte(ansi.SetHyperlink(w.link.URL, w.link.Params)))
|
||||||
|
}
|
||||||
|
if !w.style.Empty() {
|
||||||
|
_, _ = w.w.Write([]byte(w.style.Sequence()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the writer, resets the style and link if necessary, and releases
|
||||||
|
// its parser. Calling it is performance critical, but forgetting it does not
|
||||||
|
// cause safety issues or leaks.
|
||||||
|
func (w *PenWriter) Close() error {
|
||||||
|
if !w.style.Empty() {
|
||||||
|
_, _ = w.w.Write([]byte(ansi.ResetStyle))
|
||||||
|
}
|
||||||
|
if !w.link.Empty() {
|
||||||
|
_, _ = w.w.Write([]byte(ansi.ResetHyperlink()))
|
||||||
|
}
|
||||||
|
if w.p != nil {
|
||||||
|
ansi.PutParser(w.p)
|
||||||
|
w.p = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
221
vendor/github.com/charmbracelet/x/cellbuf/screen.go
generated
vendored
221
vendor/github.com/charmbracelet/x/cellbuf/screen.go
generated
vendored
@ -39,9 +39,9 @@ func relativeCursorMove(s *Screen, fx, fy, tx, ty int, overwrite, useTabs, useBa
|
|||||||
var seq strings.Builder
|
var seq strings.Builder
|
||||||
|
|
||||||
width, height := s.newbuf.Width(), s.newbuf.Height()
|
width, height := s.newbuf.Width(), s.newbuf.Height()
|
||||||
if ty != fy {
|
if ty != fy { //nolint:nestif
|
||||||
var yseq string
|
var yseq string
|
||||||
if s.xtermLike && !s.opts.RelativeCursor {
|
if s.caps.Contains(capVPA) && !s.opts.RelativeCursor {
|
||||||
yseq = ansi.VerticalPositionAbsolute(ty + 1)
|
yseq = ansi.VerticalPositionAbsolute(ty + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,9 +54,13 @@ func relativeCursorMove(s *Screen, fx, fy, tx, ty int, overwrite, useTabs, useBa
|
|||||||
}
|
}
|
||||||
shouldScroll := !s.opts.AltScreen && fy+n >= s.scrollHeight
|
shouldScroll := !s.opts.AltScreen && fy+n >= s.scrollHeight
|
||||||
if lf := strings.Repeat("\n", n); shouldScroll || (fy+n < height && len(lf) < len(yseq)) {
|
if lf := strings.Repeat("\n", n); shouldScroll || (fy+n < height && len(lf) < len(yseq)) {
|
||||||
|
//nolint:godox
|
||||||
// TODO: Ensure we're not unintentionally scrolling the screen down.
|
// TODO: Ensure we're not unintentionally scrolling the screen down.
|
||||||
yseq = lf
|
yseq = lf
|
||||||
s.scrollHeight = max(s.scrollHeight, fy+n)
|
s.scrollHeight = max(s.scrollHeight, fy+n)
|
||||||
|
if s.opts.MapNL {
|
||||||
|
fx = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if ty < fy {
|
} else if ty < fy {
|
||||||
n := fy - ty
|
n := fy - ty
|
||||||
@ -64,6 +68,7 @@ func relativeCursorMove(s *Screen, fx, fy, tx, ty int, overwrite, useTabs, useBa
|
|||||||
yseq = cuu
|
yseq = cuu
|
||||||
}
|
}
|
||||||
if n == 1 && fy-1 > 0 {
|
if n == 1 && fy-1 > 0 {
|
||||||
|
//nolint:godox
|
||||||
// TODO: Ensure we're not unintentionally scrolling the screen up.
|
// TODO: Ensure we're not unintentionally scrolling the screen up.
|
||||||
yseq = ansi.ReverseIndex
|
yseq = ansi.ReverseIndex
|
||||||
}
|
}
|
||||||
@ -72,9 +77,9 @@ func relativeCursorMove(s *Screen, fx, fy, tx, ty int, overwrite, useTabs, useBa
|
|||||||
seq.WriteString(yseq)
|
seq.WriteString(yseq)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tx != fx {
|
if tx != fx { //nolint:nestif
|
||||||
var xseq string
|
var xseq string
|
||||||
if s.xtermLike && !s.opts.RelativeCursor {
|
if s.caps.Contains(capHPA) && !s.opts.RelativeCursor {
|
||||||
xseq = ansi.HorizontalPositionAbsolute(tx + 1)
|
xseq = ansi.HorizontalPositionAbsolute(tx + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +98,8 @@ func relativeCursorMove(s *Screen, fx, fy, tx, ty int, overwrite, useTabs, useBa
|
|||||||
if tabs > 0 {
|
if tabs > 0 {
|
||||||
cht := ansi.CursorHorizontalForwardTab(tabs)
|
cht := ansi.CursorHorizontalForwardTab(tabs)
|
||||||
tab := strings.Repeat("\t", tabs)
|
tab := strings.Repeat("\t", tabs)
|
||||||
if false && s.xtermLike && len(cht) < len(tab) {
|
if false && s.caps.Contains(capCHT) && len(cht) < len(tab) {
|
||||||
|
//nolint:godox
|
||||||
// TODO: The linux console and some terminals such as
|
// TODO: The linux console and some terminals such as
|
||||||
// Alacritty don't support [ansi.CHT]. Enable this when
|
// Alacritty don't support [ansi.CHT]. Enable this when
|
||||||
// we have a way to detect this, or after 5 years when
|
// we have a way to detect this, or after 5 years when
|
||||||
@ -144,7 +150,7 @@ func relativeCursorMove(s *Screen, fx, fy, tx, ty int, overwrite, useTabs, useBa
|
|||||||
}
|
}
|
||||||
} else if tx < fx {
|
} else if tx < fx {
|
||||||
n := fx - tx
|
n := fx - tx
|
||||||
if useTabs && s.xtermLike {
|
if useTabs && s.caps.Contains(capCBT) {
|
||||||
// VT100 does not support backward tabs [ansi.CBT].
|
// VT100 does not support backward tabs [ansi.CBT].
|
||||||
|
|
||||||
col := fx
|
col := fx
|
||||||
@ -190,7 +196,7 @@ func moveCursor(s *Screen, x, y int, overwrite bool) (seq string) {
|
|||||||
// Method #0: Use [ansi.CUP] if the distance is long.
|
// Method #0: Use [ansi.CUP] if the distance is long.
|
||||||
seq = ansi.CursorPosition(x+1, y+1)
|
seq = ansi.CursorPosition(x+1, y+1)
|
||||||
if fx == -1 || fy == -1 || notLocal(s.newbuf.Width(), fx, fy, x, y) {
|
if fx == -1 || fy == -1 || notLocal(s.newbuf.Width(), fx, fy, x, y) {
|
||||||
return
|
return seq
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +240,7 @@ func moveCursor(s *Screen, x, y int, overwrite bool) (seq string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return seq
|
||||||
}
|
}
|
||||||
|
|
||||||
// moveCursor moves the cursor to the specified position.
|
// moveCursor moves the cursor to the specified position.
|
||||||
@ -242,10 +248,10 @@ func (s *Screen) moveCursor(x, y int, overwrite bool) {
|
|||||||
if !s.opts.AltScreen && s.cur.X == -1 && s.cur.Y == -1 {
|
if !s.opts.AltScreen && s.cur.X == -1 && s.cur.Y == -1 {
|
||||||
// First cursor movement in inline mode, move the cursor to the first
|
// First cursor movement in inline mode, move the cursor to the first
|
||||||
// column before moving to the target position.
|
// column before moving to the target position.
|
||||||
s.buf.WriteByte('\r') //nolint:errcheck
|
s.buf.WriteByte('\r')
|
||||||
s.cur.X, s.cur.Y = 0, 0
|
s.cur.X, s.cur.Y = 0, 0
|
||||||
}
|
}
|
||||||
s.buf.WriteString(moveCursor(s, x, y, overwrite)) //nolint:errcheck
|
s.buf.WriteString(moveCursor(s, x, y, overwrite))
|
||||||
s.cur.X, s.cur.Y = x, y
|
s.cur.X, s.cur.Y = x, y
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,10 +280,11 @@ func (s *Screen) move(x, y int) {
|
|||||||
// Reset wrap around (phantom cursor) state
|
// Reset wrap around (phantom cursor) state
|
||||||
if s.atPhantom {
|
if s.atPhantom {
|
||||||
s.cur.X = 0
|
s.cur.X = 0
|
||||||
s.buf.WriteByte('\r') //nolint:errcheck
|
s.buf.WriteByte('\r')
|
||||||
s.atPhantom = false // reset phantom cell state
|
s.atPhantom = false // reset phantom cell state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:godox
|
||||||
// TODO: Investigate if we need to handle this case and/or if we need the
|
// TODO: Investigate if we need to handle this case and/or if we need the
|
||||||
// following code.
|
// following code.
|
||||||
//
|
//
|
||||||
@ -291,7 +298,7 @@ func (s *Screen) move(x, y int) {
|
|||||||
//
|
//
|
||||||
// if l > 0 {
|
// if l > 0 {
|
||||||
// s.cur.X = 0
|
// s.cur.X = 0
|
||||||
// s.buf.WriteString("\r" + strings.Repeat("\n", l)) //nolint:errcheck
|
// s.buf.WriteString("\r" + strings.Repeat("\n", l))
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@ -339,6 +346,10 @@ type ScreenOptions struct {
|
|||||||
HardTabs bool
|
HardTabs bool
|
||||||
// Backspace is whether to use backspace characters to move the cursor.
|
// Backspace is whether to use backspace characters to move the cursor.
|
||||||
Backspace bool
|
Backspace bool
|
||||||
|
// MapNL whether we have ONLCR mapping enabled. When we set the terminal to
|
||||||
|
// raw mode, the ONLCR mode gets disabled. ONLCR maps any newline/linefeed
|
||||||
|
// (`\n`) character to carriage return + line feed (`\r\n`).
|
||||||
|
MapNL bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// lineData represents the metadata for a line.
|
// lineData represents the metadata for a line.
|
||||||
@ -365,13 +376,13 @@ type Screen struct {
|
|||||||
opts ScreenOptions
|
opts ScreenOptions
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
method ansi.Method
|
method ansi.Method
|
||||||
scrollHeight int // keeps track of how many lines we've scrolled down (inline mode)
|
scrollHeight int // keeps track of how many lines we've scrolled down (inline mode)
|
||||||
altScreenMode bool // whether alternate screen mode is enabled
|
altScreenMode bool // whether alternate screen mode is enabled
|
||||||
cursorHidden bool // whether text cursor mode is enabled
|
cursorHidden bool // whether text cursor mode is enabled
|
||||||
clear bool // whether to force clear the screen
|
clear bool // whether to force clear the screen
|
||||||
xtermLike bool // whether to use xterm-like optimizations, otherwise, it uses vt100 only
|
caps capabilities // terminal control sequence capabilities
|
||||||
queuedText bool // whether we have queued non-zero width text queued up
|
queuedText bool // whether we have queued non-zero width text queued up
|
||||||
atPhantom bool // whether the cursor is out of bounds and at a phantom cell
|
atPhantom bool // whether the cursor is out of bounds and at a phantom cell
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMethod sets the method used to calculate the width of cells.
|
// SetMethod sets the method used to calculate the width of cells.
|
||||||
@ -491,36 +502,77 @@ func (s *Screen) FillRect(cell *Cell, r Rectangle) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// isXtermLike returns whether the terminal is xterm-like. This means that the
|
// capabilities represents a mask of supported ANSI escape sequences.
|
||||||
|
type capabilities uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Vertical Position Absolute [ansi.VPA].
|
||||||
|
capVPA capabilities = 1 << iota
|
||||||
|
// Horizontal Position Absolute [ansi.HPA].
|
||||||
|
capHPA
|
||||||
|
// Cursor Horizontal Tab [ansi.CHT].
|
||||||
|
capCHT
|
||||||
|
// Cursor Backward Tab [ansi.CBT].
|
||||||
|
capCBT
|
||||||
|
// Repeat Previous Character [ansi.REP].
|
||||||
|
capREP
|
||||||
|
// Erase Character [ansi.ECH].
|
||||||
|
capECH
|
||||||
|
// Insert Character [ansi.ICH].
|
||||||
|
capICH
|
||||||
|
// Scroll Down [ansi.SD].
|
||||||
|
capSD
|
||||||
|
// Scroll Up [ansi.SU].
|
||||||
|
capSU
|
||||||
|
|
||||||
|
noCaps capabilities = 0
|
||||||
|
allCaps = capVPA | capHPA | capCHT | capCBT | capREP | capECH | capICH |
|
||||||
|
capSD | capSU
|
||||||
|
)
|
||||||
|
|
||||||
|
// Contains returns whether the capabilities contains the given capability.
|
||||||
|
func (v capabilities) Contains(c capabilities) bool {
|
||||||
|
return v&c == c
|
||||||
|
}
|
||||||
|
|
||||||
|
// xtermCaps returns whether the terminal is xterm-like. This means that the
|
||||||
// terminal supports ECMA-48 and ANSI X3.64 escape sequences.
|
// terminal supports ECMA-48 and ANSI X3.64 escape sequences.
|
||||||
// TODO: Should this be a lookup table into each $TERM terminfo database? Like
|
// xtermCaps returns a list of control sequence capabilities for the given
|
||||||
// we could keep a map of ANSI escape sequence to terminfo capability name and
|
// terminal type. This only supports a subset of sequences that can
|
||||||
// check if the database supports the escape sequence. Instead of keeping a
|
// be different among terminals.
|
||||||
// list of terminal names here.
|
// NOTE: A hybrid approach would be to support Terminfo databases for a full
|
||||||
func isXtermLike(termtype string) (v bool) {
|
// set of capabilities.
|
||||||
|
func xtermCaps(termtype string) (v capabilities) {
|
||||||
parts := strings.Split(termtype, "-")
|
parts := strings.Split(termtype, "-")
|
||||||
if len(parts) == 0 {
|
if len(parts) == 0 {
|
||||||
return
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
switch parts[0] {
|
switch parts[0] {
|
||||||
case
|
case
|
||||||
"alacritty",
|
|
||||||
"contour",
|
"contour",
|
||||||
"foot",
|
"foot",
|
||||||
"ghostty",
|
"ghostty",
|
||||||
"kitty",
|
"kitty",
|
||||||
"linux",
|
|
||||||
"rio",
|
"rio",
|
||||||
"screen",
|
|
||||||
"st",
|
"st",
|
||||||
"tmux",
|
"tmux",
|
||||||
"wezterm",
|
"wezterm",
|
||||||
"xterm":
|
"xterm":
|
||||||
v = true
|
v = allCaps
|
||||||
|
case "alacritty":
|
||||||
|
v = allCaps
|
||||||
|
v &^= capCHT // NOTE: alacritty added support for [ansi.CHT] in 2024-12-28 #62d5b13.
|
||||||
|
case "screen":
|
||||||
|
// See https://www.gnu.org/software/screen/manual/screen.html#Control-Sequences-1
|
||||||
|
v = allCaps
|
||||||
|
v &^= capREP
|
||||||
|
case "linux":
|
||||||
|
// See https://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||||
|
v = capVPA | capHPA | capECH | capICH
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScreen creates a new Screen.
|
// NewScreen creates a new Screen.
|
||||||
@ -548,14 +600,14 @@ func NewScreen(w io.Writer, width, height int, opts *ScreenOptions) (s *Screen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.buf = new(bytes.Buffer)
|
s.buf = new(bytes.Buffer)
|
||||||
s.xtermLike = isXtermLike(s.opts.Term)
|
s.caps = xtermCaps(s.opts.Term)
|
||||||
s.curbuf = NewBuffer(width, height)
|
s.curbuf = NewBuffer(width, height)
|
||||||
s.newbuf = NewBuffer(width, height)
|
s.newbuf = NewBuffer(width, height)
|
||||||
s.cur = Cursor{Position: Pos(-1, -1)} // start at -1 to force a move
|
s.cur = Cursor{Position: Pos(-1, -1)} // start at -1 to force a move
|
||||||
s.saved = s.cur
|
s.saved = s.cur
|
||||||
s.reset()
|
s.reset()
|
||||||
|
|
||||||
return
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Width returns the width of the screen.
|
// Width returns the width of the screen.
|
||||||
@ -595,7 +647,7 @@ func (s *Screen) putCell(cell *Cell) {
|
|||||||
|
|
||||||
// wrapCursor wraps the cursor to the next line.
|
// wrapCursor wraps the cursor to the next line.
|
||||||
//
|
//
|
||||||
//nolint:unused
|
|
||||||
func (s *Screen) wrapCursor() {
|
func (s *Screen) wrapCursor() {
|
||||||
const autoRightMargin = true
|
const autoRightMargin = true
|
||||||
if autoRightMargin {
|
if autoRightMargin {
|
||||||
@ -628,9 +680,9 @@ func (s *Screen) putAttrCell(cell *Cell) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.updatePen(cell)
|
s.updatePen(cell)
|
||||||
s.buf.WriteRune(cell.Rune) //nolint:errcheck
|
s.buf.WriteRune(cell.Rune)
|
||||||
for _, c := range cell.Comb {
|
for _, c := range cell.Comb {
|
||||||
s.buf.WriteRune(c) //nolint:errcheck
|
s.buf.WriteRune(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cur.X += cell.Width
|
s.cur.X += cell.Width
|
||||||
@ -649,12 +701,12 @@ func (s *Screen) putCellLR(cell *Cell) {
|
|||||||
// Optimize for the lower right corner cell.
|
// Optimize for the lower right corner cell.
|
||||||
curX := s.cur.X
|
curX := s.cur.X
|
||||||
if cell == nil || !cell.Empty() {
|
if cell == nil || !cell.Empty() {
|
||||||
s.buf.WriteString(ansi.ResetAutoWrapMode) //nolint:errcheck
|
s.buf.WriteString(ansi.ResetModeAutoWrap)
|
||||||
s.putAttrCell(cell)
|
s.putAttrCell(cell)
|
||||||
// Writing to lower-right corner cell should not wrap.
|
// Writing to lower-right corner cell should not wrap.
|
||||||
s.atPhantom = false
|
s.atPhantom = false
|
||||||
s.cur.X = curX
|
s.cur.X = curX
|
||||||
s.buf.WriteString(ansi.SetAutoWrapMode) //nolint:errcheck
|
s.buf.WriteString(ansi.SetModeAutoWrap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -675,11 +727,11 @@ func (s *Screen) updatePen(cell *Cell) {
|
|||||||
if cell.Style.Empty() && len(seq) > len(ansi.ResetStyle) {
|
if cell.Style.Empty() && len(seq) > len(ansi.ResetStyle) {
|
||||||
seq = ansi.ResetStyle
|
seq = ansi.ResetStyle
|
||||||
}
|
}
|
||||||
s.buf.WriteString(seq) //nolint:errcheck
|
s.buf.WriteString(seq)
|
||||||
s.cur.Style = cell.Style
|
s.cur.Style = cell.Style
|
||||||
}
|
}
|
||||||
if !cell.Link.Equal(&s.cur.Link) {
|
if !cell.Link.Equal(&s.cur.Link) {
|
||||||
s.buf.WriteString(ansi.SetHyperlink(cell.Link.URL, cell.Link.Params)) //nolint:errcheck
|
s.buf.WriteString(ansi.SetHyperlink(cell.Link.URL, cell.Link.Params))
|
||||||
s.cur.Link = cell.Link
|
s.cur.Link = cell.Link
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -712,9 +764,9 @@ func (s *Screen) emitRange(line Line, n int) (eoi bool) {
|
|||||||
ech := ansi.EraseCharacter(count)
|
ech := ansi.EraseCharacter(count)
|
||||||
cup := ansi.CursorPosition(s.cur.X+count, s.cur.Y)
|
cup := ansi.CursorPosition(s.cur.X+count, s.cur.Y)
|
||||||
rep := ansi.RepeatPreviousCharacter(count)
|
rep := ansi.RepeatPreviousCharacter(count)
|
||||||
if s.xtermLike && count > len(ech)+len(cup) && cell0 != nil && cell0.Clear() {
|
if s.caps.Contains(capECH) && count > len(ech)+len(cup) && cell0 != nil && cell0.Clear() { //nolint:nestif
|
||||||
s.updatePen(cell0)
|
s.updatePen(cell0)
|
||||||
s.buf.WriteString(ech) //nolint:errcheck
|
s.buf.WriteString(ech)
|
||||||
|
|
||||||
// If this is the last cell, we don't need to move the cursor.
|
// If this is the last cell, we don't need to move the cursor.
|
||||||
if count < n {
|
if count < n {
|
||||||
@ -722,7 +774,7 @@ func (s *Screen) emitRange(line Line, n int) (eoi bool) {
|
|||||||
} else {
|
} else {
|
||||||
return true // cursor in the middle
|
return true // cursor in the middle
|
||||||
}
|
}
|
||||||
} else if s.xtermLike && count > len(rep) &&
|
} else if s.caps.Contains(capREP) && count > len(rep) &&
|
||||||
(cell0 == nil || (len(cell0.Comb) == 0 && cell0.Rune < 256)) {
|
(cell0 == nil || (len(cell0.Comb) == 0 && cell0.Rune < 256)) {
|
||||||
// We only support ASCII characters. Most terminals will handle
|
// We only support ASCII characters. Most terminals will handle
|
||||||
// non-ASCII characters correctly, but some might not, ahem xterm.
|
// non-ASCII characters correctly, but some might not, ahem xterm.
|
||||||
@ -740,13 +792,13 @@ func (s *Screen) emitRange(line Line, n int) (eoi bool) {
|
|||||||
s.putCell(cell0)
|
s.putCell(cell0)
|
||||||
repCount-- // cell0 is a single width cell ASCII character
|
repCount-- // cell0 is a single width cell ASCII character
|
||||||
|
|
||||||
s.buf.WriteString(ansi.RepeatPreviousCharacter(repCount)) //nolint:errcheck
|
s.buf.WriteString(ansi.RepeatPreviousCharacter(repCount))
|
||||||
s.cur.X += repCount
|
s.cur.X += repCount
|
||||||
if wrapPossible {
|
if wrapPossible {
|
||||||
s.putCell(cell0)
|
s.putCell(cell0)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < count; i++ {
|
for i := range count {
|
||||||
s.putCell(line.At(i))
|
s.putCell(line.At(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -755,7 +807,7 @@ func (s *Screen) emitRange(line Line, n int) (eoi bool) {
|
|||||||
n -= count
|
n -= count
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return eoi
|
||||||
}
|
}
|
||||||
|
|
||||||
// putRange puts a range of cells from the old line to the new line.
|
// putRange puts a range of cells from the old line to the new line.
|
||||||
@ -765,7 +817,7 @@ func (s *Screen) putRange(oldLine, newLine Line, y, start, end int) (eoi bool) {
|
|||||||
inline := min(len(ansi.CursorPosition(start+1, y+1)),
|
inline := min(len(ansi.CursorPosition(start+1, y+1)),
|
||||||
min(len(ansi.HorizontalPositionAbsolute(start+1)),
|
min(len(ansi.HorizontalPositionAbsolute(start+1)),
|
||||||
len(ansi.CursorForward(start+1))))
|
len(ansi.CursorForward(start+1))))
|
||||||
if (end - start + 1) > inline {
|
if (end - start + 1) > inline { //nolint:nestif
|
||||||
var j, same int
|
var j, same int
|
||||||
for j, same = start, 0; j <= end; j++ {
|
for j, same = start, 0; j <= end; j++ {
|
||||||
oldCell, newCell := oldLine.At(j), newLine.At(j)
|
oldCell, newCell := oldLine.At(j), newLine.At(j)
|
||||||
@ -817,9 +869,9 @@ func (s *Screen) clearToEnd(blank *Cell, force bool) { //nolint:unparam
|
|||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
count := s.newbuf.Width() - s.cur.X
|
count := s.newbuf.Width() - s.cur.X
|
||||||
if s.el0Cost() <= count {
|
if s.el0Cost() <= count {
|
||||||
s.buf.WriteString(ansi.EraseLineRight) //nolint:errcheck
|
s.buf.WriteString(ansi.EraseLineRight)
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < count; i++ {
|
for range count {
|
||||||
s.putCell(blank)
|
s.putCell(blank)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -839,12 +891,13 @@ func (s *Screen) clearBlank() *Cell {
|
|||||||
// insertCells inserts the count cells pointed by the given line at the current
|
// insertCells inserts the count cells pointed by the given line at the current
|
||||||
// cursor position.
|
// cursor position.
|
||||||
func (s *Screen) insertCells(line Line, count int) {
|
func (s *Screen) insertCells(line Line, count int) {
|
||||||
if s.xtermLike {
|
supportsICH := s.caps.Contains(capICH)
|
||||||
|
if supportsICH {
|
||||||
// Use [ansi.ICH] as an optimization.
|
// Use [ansi.ICH] as an optimization.
|
||||||
s.buf.WriteString(ansi.InsertCharacter(count)) //nolint:errcheck
|
s.buf.WriteString(ansi.InsertCharacter(count))
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, use [ansi.IRM] mode.
|
// Otherwise, use [ansi.IRM] mode.
|
||||||
s.buf.WriteString(ansi.SetInsertReplaceMode) //nolint:errcheck
|
s.buf.WriteString(ansi.SetModeInsertReplace)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; count > 0; i++ {
|
for i := 0; count > 0; i++ {
|
||||||
@ -852,8 +905,8 @@ func (s *Screen) insertCells(line Line, count int) {
|
|||||||
count--
|
count--
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.xtermLike {
|
if !supportsICH {
|
||||||
s.buf.WriteString(ansi.ResetInsertReplaceMode) //nolint:errcheck
|
s.buf.WriteString(ansi.ResetModeInsertReplace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,7 +915,7 @@ func (s *Screen) insertCells(line Line, count int) {
|
|||||||
// [ansi.EL] 0 i.e. [ansi.EraseLineRight] to clear
|
// [ansi.EL] 0 i.e. [ansi.EraseLineRight] to clear
|
||||||
// trailing spaces.
|
// trailing spaces.
|
||||||
func (s *Screen) el0Cost() int {
|
func (s *Screen) el0Cost() int {
|
||||||
if s.xtermLike {
|
if s.caps != noCaps {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return len(ansi.EraseLineRight)
|
return len(ansi.EraseLineRight)
|
||||||
@ -878,7 +931,7 @@ func (s *Screen) transformLine(y int) {
|
|||||||
|
|
||||||
// Find the first changed cell in the line
|
// Find the first changed cell in the line
|
||||||
var lineChanged bool
|
var lineChanged bool
|
||||||
for i := 0; i < s.newbuf.Width(); i++ {
|
for i := range s.newbuf.Width() {
|
||||||
if !cellEqual(newLine.At(i), oldLine.At(i)) {
|
if !cellEqual(newLine.At(i), oldLine.At(i)) {
|
||||||
lineChanged = true
|
lineChanged = true
|
||||||
break
|
break
|
||||||
@ -886,7 +939,7 @@ func (s *Screen) transformLine(y int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ceolStandoutGlitch = false
|
const ceolStandoutGlitch = false
|
||||||
if ceolStandoutGlitch && lineChanged {
|
if ceolStandoutGlitch && lineChanged { //nolint:nestif
|
||||||
s.move(0, y)
|
s.move(0, y)
|
||||||
s.clearToEnd(nil, false)
|
s.clearToEnd(nil, false)
|
||||||
s.putRange(oldLine, newLine, y, 0, s.newbuf.Width()-1)
|
s.putRange(oldLine, newLine, y, 0, s.newbuf.Width()-1)
|
||||||
@ -897,12 +950,12 @@ func (s *Screen) transformLine(y int) {
|
|||||||
// [ansi.EraseLineLeft].
|
// [ansi.EraseLineLeft].
|
||||||
if blank == nil || blank.Clear() {
|
if blank == nil || blank.Clear() {
|
||||||
var oFirstCell, nFirstCell int
|
var oFirstCell, nFirstCell int
|
||||||
for oFirstCell = 0; oFirstCell < s.curbuf.Width(); oFirstCell++ {
|
for oFirstCell = range s.curbuf.Width() {
|
||||||
if !cellEqual(oldLine.At(oFirstCell), blank) {
|
if !cellEqual(oldLine.At(oFirstCell), blank) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for nFirstCell = 0; nFirstCell < s.newbuf.Width(); nFirstCell++ {
|
for nFirstCell = range s.newbuf.Width() {
|
||||||
if !cellEqual(newLine.At(nFirstCell), blank) {
|
if !cellEqual(newLine.At(nFirstCell), blank) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -925,11 +978,11 @@ func (s *Screen) transformLine(y int) {
|
|||||||
if nFirstCell >= s.newbuf.Width() {
|
if nFirstCell >= s.newbuf.Width() {
|
||||||
s.move(0, y)
|
s.move(0, y)
|
||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
s.buf.WriteString(ansi.EraseLineRight) //nolint:errcheck
|
s.buf.WriteString(ansi.EraseLineRight)
|
||||||
} else {
|
} else {
|
||||||
s.move(nFirstCell-1, y)
|
s.move(nFirstCell-1, y)
|
||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
s.buf.WriteString(ansi.EraseLineLeft) //nolint:errcheck
|
s.buf.WriteString(ansi.EraseLineLeft)
|
||||||
}
|
}
|
||||||
|
|
||||||
for firstCell < nFirstCell {
|
for firstCell < nFirstCell {
|
||||||
@ -1045,7 +1098,7 @@ func (s *Screen) transformLine(y int) {
|
|||||||
|
|
||||||
s.move(n+1, y)
|
s.move(n+1, y)
|
||||||
ichCost := 3 + nLastCell - oLastCell
|
ichCost := 3 + nLastCell - oLastCell
|
||||||
if s.xtermLike && (nLastCell < nLastNonBlank || ichCost > (m-n)) {
|
if s.caps.Contains(capICH) && (nLastCell < nLastNonBlank || ichCost > (m-n)) {
|
||||||
s.putRange(oldLine, newLine, y, n+1, m)
|
s.putRange(oldLine, newLine, y, n+1, m)
|
||||||
} else {
|
} else {
|
||||||
s.insertCells(newLine[n+1:], nLastCell-oLastCell)
|
s.insertCells(newLine[n+1:], nLastCell-oLastCell)
|
||||||
@ -1079,7 +1132,7 @@ func (s *Screen) transformLine(y int) {
|
|||||||
func (s *Screen) deleteCells(count int) {
|
func (s *Screen) deleteCells(count int) {
|
||||||
// [ansi.DCH] will shift in cells from the right margin so we need to
|
// [ansi.DCH] will shift in cells from the right margin so we need to
|
||||||
// ensure that they are the right style.
|
// ensure that they are the right style.
|
||||||
s.buf.WriteString(ansi.DeleteCharacter(count)) //nolint:errcheck
|
s.buf.WriteString(ansi.DeleteCharacter(count))
|
||||||
}
|
}
|
||||||
|
|
||||||
// clearToBottom clears the screen from the current cursor position to the end
|
// clearToBottom clears the screen from the current cursor position to the end
|
||||||
@ -1091,7 +1144,7 @@ func (s *Screen) clearToBottom(blank *Cell) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
s.buf.WriteString(ansi.EraseScreenBelow) //nolint:errcheck
|
s.buf.WriteString(ansi.EraseScreenBelow)
|
||||||
// Clear the rest of the current line
|
// Clear the rest of the current line
|
||||||
s.curbuf.ClearRect(Rect(col, row, s.curbuf.Width()-col, 1))
|
s.curbuf.ClearRect(Rect(col, row, s.curbuf.Width()-col, 1))
|
||||||
// Clear everything below the current line
|
// Clear everything below the current line
|
||||||
@ -1104,7 +1157,7 @@ func (s *Screen) clearToBottom(blank *Cell) {
|
|||||||
// It returns the top line.
|
// It returns the top line.
|
||||||
func (s *Screen) clearBottom(total int) (top int) {
|
func (s *Screen) clearBottom(total int) (top int) {
|
||||||
if total <= 0 {
|
if total <= 0 {
|
||||||
return
|
return top
|
||||||
}
|
}
|
||||||
|
|
||||||
top = total
|
top = total
|
||||||
@ -1112,7 +1165,7 @@ func (s *Screen) clearBottom(total int) (top int) {
|
|||||||
blank := s.clearBlank()
|
blank := s.clearBlank()
|
||||||
canClearWithBlank := blank == nil || blank.Clear()
|
canClearWithBlank := blank == nil || blank.Clear()
|
||||||
|
|
||||||
if canClearWithBlank {
|
if canClearWithBlank { //nolint:nestif
|
||||||
var row int
|
var row int
|
||||||
for row = total - 1; row >= 0; row-- {
|
for row = total - 1; row >= 0; row-- {
|
||||||
oldLine := s.curbuf.Line(row)
|
oldLine := s.curbuf.Line(row)
|
||||||
@ -1147,14 +1200,14 @@ func (s *Screen) clearBottom(total int) (top int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return top
|
||||||
}
|
}
|
||||||
|
|
||||||
// clearScreen clears the screen and put cursor at home.
|
// clearScreen clears the screen and put cursor at home.
|
||||||
func (s *Screen) clearScreen(blank *Cell) {
|
func (s *Screen) clearScreen(blank *Cell) {
|
||||||
s.updatePen(blank)
|
s.updatePen(blank)
|
||||||
s.buf.WriteString(ansi.CursorHomePosition) //nolint:errcheck
|
s.buf.WriteString(ansi.CursorHomePosition)
|
||||||
s.buf.WriteString(ansi.EraseEntireScreen) //nolint:errcheck
|
s.buf.WriteString(ansi.EraseEntireScreen)
|
||||||
s.cur.X, s.cur.Y = 0, 0
|
s.cur.X, s.cur.Y = 0, 0
|
||||||
s.curbuf.Fill(blank)
|
s.curbuf.Fill(blank)
|
||||||
}
|
}
|
||||||
@ -1179,7 +1232,7 @@ func (s *Screen) clearUpdate() {
|
|||||||
s.clearBelow(blank, 0)
|
s.clearBelow(blank, 0)
|
||||||
}
|
}
|
||||||
nonEmpty = s.clearBottom(nonEmpty)
|
nonEmpty = s.clearBottom(nonEmpty)
|
||||||
for i := 0; i < nonEmpty; i++ {
|
for i := range nonEmpty {
|
||||||
s.transformLine(i)
|
s.transformLine(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1194,13 +1247,13 @@ func (s *Screen) Flush() (err error) {
|
|||||||
func (s *Screen) flush() (err error) {
|
func (s *Screen) flush() (err error) {
|
||||||
// Write the buffer
|
// Write the buffer
|
||||||
if s.buf.Len() > 0 {
|
if s.buf.Len() > 0 {
|
||||||
_, err = s.w.Write(s.buf.Bytes()) //nolint:errcheck
|
_, err = s.w.Write(s.buf.Bytes())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
s.buf.Reset()
|
s.buf.Reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return err //nolint:wrapcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render renders changes of the screen to the internal buffer. Call
|
// Render renders changes of the screen to the internal buffer. Call
|
||||||
@ -1221,6 +1274,7 @@ func (s *Screen) render() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:godox
|
||||||
// TODO: Investigate whether this is necessary. Theoretically, terminals
|
// TODO: Investigate whether this is necessary. Theoretically, terminals
|
||||||
// can add/remove tab stops and we should be able to handle that. We could
|
// can add/remove tab stops and we should be able to handle that. We could
|
||||||
// use [ansi.DECTABSR] to read the tab stops, but that's not implemented in
|
// use [ansi.DECTABSR] to read the tab stops, but that's not implemented in
|
||||||
@ -1235,9 +1289,9 @@ func (s *Screen) render() {
|
|||||||
// Do we need alt-screen mode?
|
// Do we need alt-screen mode?
|
||||||
if s.opts.AltScreen != s.altScreenMode {
|
if s.opts.AltScreen != s.altScreenMode {
|
||||||
if s.opts.AltScreen {
|
if s.opts.AltScreen {
|
||||||
s.buf.WriteString(ansi.SetAltScreenSaveCursorMode)
|
s.buf.WriteString(ansi.SetModeAltScreenSaveCursor)
|
||||||
} else {
|
} else {
|
||||||
s.buf.WriteString(ansi.ResetAltScreenSaveCursorMode)
|
s.buf.WriteString(ansi.ResetModeAltScreenSaveCursor)
|
||||||
}
|
}
|
||||||
s.altScreenMode = s.opts.AltScreen
|
s.altScreenMode = s.opts.AltScreen
|
||||||
}
|
}
|
||||||
@ -1252,7 +1306,9 @@ func (s *Screen) render() {
|
|||||||
|
|
||||||
// Do we have queued strings to write above the screen?
|
// Do we have queued strings to write above the screen?
|
||||||
if len(s.queueAbove) > 0 {
|
if len(s.queueAbove) > 0 {
|
||||||
|
//nolint:godox
|
||||||
// TODO: Use scrolling region if available.
|
// TODO: Use scrolling region if available.
|
||||||
|
//nolint:godox
|
||||||
// TODO: Use [Screen.Write] [io.Writer] interface.
|
// TODO: Use [Screen.Write] [io.Writer] interface.
|
||||||
|
|
||||||
// We need to scroll the screen up by the number of lines in the queue.
|
// We need to scroll the screen up by the number of lines in the queue.
|
||||||
@ -1290,12 +1346,13 @@ func (s *Screen) render() {
|
|||||||
s.clearBelow(nil, s.newbuf.Height()-1)
|
s.clearBelow(nil, s.newbuf.Height()-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.clear {
|
if s.clear { //nolint:nestif
|
||||||
s.clearUpdate()
|
s.clearUpdate()
|
||||||
s.clear = false
|
s.clear = false
|
||||||
} else if len(s.touch) > 0 {
|
} else if len(s.touch) > 0 {
|
||||||
if s.opts.AltScreen {
|
if s.opts.AltScreen {
|
||||||
// Optimize scrolling for the alternate screen buffer.
|
// Optimize scrolling for the alternate screen buffer.
|
||||||
|
//nolint:godox
|
||||||
// TODO: Should we optimize for inline mode as well? If so, we need
|
// TODO: Should we optimize for inline mode as well? If so, we need
|
||||||
// to know the actual cursor position to use [ansi.DECSTBM].
|
// to know the actual cursor position to use [ansi.DECSTBM].
|
||||||
s.scrollOptimize()
|
s.scrollOptimize()
|
||||||
@ -1311,7 +1368,7 @@ func (s *Screen) render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nonEmpty = s.clearBottom(nonEmpty)
|
nonEmpty = s.clearBottom(nonEmpty)
|
||||||
for i = 0; i < nonEmpty; i++ {
|
for i = range nonEmpty {
|
||||||
_, ok := s.touch[i]
|
_, ok := s.touch[i]
|
||||||
if ok {
|
if ok {
|
||||||
s.transformLine(i)
|
s.transformLine(i)
|
||||||
@ -1359,7 +1416,7 @@ func (s *Screen) Close() (err error) {
|
|||||||
s.move(0, s.newbuf.Height()-1)
|
s.move(0, s.newbuf.Height()-1)
|
||||||
|
|
||||||
if s.altScreenMode {
|
if s.altScreenMode {
|
||||||
s.buf.WriteString(ansi.ResetAltScreenSaveCursorMode)
|
s.buf.WriteString(ansi.ResetModeAltScreenSaveCursor)
|
||||||
s.altScreenMode = false
|
s.altScreenMode = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1371,11 +1428,11 @@ func (s *Screen) Close() (err error) {
|
|||||||
// Write the buffer
|
// Write the buffer
|
||||||
err = s.flush()
|
err = s.flush()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.reset()
|
s.reset()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset resets the screen to its initial state.
|
// reset resets the screen to its initial state.
|
||||||
@ -1420,9 +1477,9 @@ func (s *Screen) Resize(width, height int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if height > oldh {
|
if height > oldh {
|
||||||
s.ClearRect(Rect(0, max(oldh-1, 0), width, height-oldh))
|
s.ClearRect(Rect(0, max(oldh, 0), width, height-oldh))
|
||||||
} else if height < oldh {
|
} else if height < oldh {
|
||||||
s.ClearRect(Rect(0, max(height-1, 0), width, oldh-height))
|
s.ClearRect(Rect(0, max(height, 0), width, oldh-height))
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
|
|||||||
4
vendor/github.com/charmbracelet/x/cellbuf/style.go
generated
vendored
4
vendor/github.com/charmbracelet/x/cellbuf/style.go
generated
vendored
@ -4,9 +4,9 @@ import (
|
|||||||
"github.com/charmbracelet/colorprofile"
|
"github.com/charmbracelet/colorprofile"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Convert converts a style to respect the given color profile.
|
// ConvertStyle converts a style to respect the given color profile.
|
||||||
func ConvertStyle(s Style, p colorprofile.Profile) Style {
|
func ConvertStyle(s Style, p colorprofile.Profile) Style {
|
||||||
switch p {
|
switch p { //nolint:exhaustive
|
||||||
case colorprofile.TrueColor:
|
case colorprofile.TrueColor:
|
||||||
return s
|
return s
|
||||||
case colorprofile.Ascii:
|
case colorprofile.Ascii:
|
||||||
|
|||||||
14
vendor/github.com/charmbracelet/x/cellbuf/utils.go
generated
vendored
14
vendor/github.com/charmbracelet/x/cellbuf/utils.go
generated
vendored
@ -9,20 +9,6 @@ func Height(s string) int {
|
|||||||
return strings.Count(s, "\n") + 1
|
return strings.Count(s, "\n") + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func min(a, b int) int { //nolint:predeclared
|
|
||||||
if a > b {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(a, b int) int { //nolint:predeclared
|
|
||||||
if a > b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func clamp(v, low, high int) int {
|
func clamp(v, low, high int) int {
|
||||||
if high < low {
|
if high < low {
|
||||||
low, high = high, low
|
low, high = high, low
|
||||||
|
|||||||
20
vendor/github.com/charmbracelet/x/cellbuf/wrap.go
generated
vendored
20
vendor/github.com/charmbracelet/x/cellbuf/wrap.go
generated
vendored
@ -2,6 +2,7 @@ package cellbuf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"slices"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@ -20,6 +21,16 @@ const nbsp = '\u00a0'
|
|||||||
//
|
//
|
||||||
// Note: breakpoints must be a string of 1-cell wide rune characters.
|
// Note: breakpoints must be a string of 1-cell wide rune characters.
|
||||||
func Wrap(s string, limit int, breakpoints string) string {
|
func Wrap(s string, limit int, breakpoints string) string {
|
||||||
|
//nolint:godox
|
||||||
|
// TODO: Use [PenWriter] once we get
|
||||||
|
// https://github.com/charmbracelet/lipgloss/pull/489 out the door and
|
||||||
|
// released.
|
||||||
|
// The problem is that [ansi.Wrap] doesn't keep track of style and link
|
||||||
|
// state, so combining both breaks styled space cells. To fix this, we use
|
||||||
|
// non-breaking space cells for padding and styled blank cells. And since
|
||||||
|
// both wrapping methods respect non-breaking spaces, we can use them to
|
||||||
|
// preserve styled spaces in the output.
|
||||||
|
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -90,7 +101,7 @@ func Wrap(s string, limit int, breakpoints string) string {
|
|||||||
seq, width, n, newState := ansi.DecodeSequence(s, state, p)
|
seq, width, n, newState := ansi.DecodeSequence(s, state, p)
|
||||||
switch width {
|
switch width {
|
||||||
case 0:
|
case 0:
|
||||||
if ansi.Equal(seq, "\t") {
|
if ansi.Equal(seq, "\t") { //nolint:nestif
|
||||||
addWord()
|
addWord()
|
||||||
space.WriteString(seq)
|
space.WriteString(seq)
|
||||||
break
|
break
|
||||||
@ -176,10 +187,5 @@ func Wrap(s string, limit int, breakpoints string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runeContainsAny[T string | []rune](r rune, s T) bool {
|
func runeContainsAny[T string | []rune](r rune, s T) bool {
|
||||||
for _, c := range []rune(s) {
|
return slices.Contains([]rune(s), r)
|
||||||
if c == r {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user