feat: implement new and man for plugin modules
- use extracted shared libraries
This commit is contained in:
parent
f2ac6e1549
commit
e60726ef9e
|
@ -4,7 +4,7 @@ buildr {
|
|||
logs_dir = ".buildr/logs"
|
||||
|
||||
plugin "golang" {
|
||||
url = "file:///home/baez/sources/Gitea/buildr/golang-plugin/golang.wasm"
|
||||
checksum = "8c339abb97dd2caa8cb219b371563273e414ae9bb362d74b01b3d19dcc46f6ab"
|
||||
url = "https://code.icb4dc0.de/api/packages/buildr/generic/golang_plugin/0.0.1/golang.wasm"
|
||||
checksum = "2a183eb9c2c55b8ab678e9f176c60a477a2d0a67e3e8d25f42bc2113e0cdab8e"
|
||||
}
|
||||
}
|
44
.drone.yml
44
.drone.yml
|
@ -3,22 +3,20 @@ kind: pipeline
|
|||
type: docker
|
||||
name: default
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: arm64
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
- tag
|
||||
refs:
|
||||
include:
|
||||
- refs/heads/main
|
||||
- refs/pull/**
|
||||
- refs/tags/**
|
||||
|
||||
steps:
|
||||
- name: Generate protobuf files
|
||||
image: bufbuild/buf
|
||||
commands:
|
||||
- buf generate
|
||||
|
||||
- name: Go generate
|
||||
image: docker.io/golang:1.20-alpine
|
||||
depends_on:
|
||||
- Generate protobuf files
|
||||
image: docker.io/golang:1.21-alpine
|
||||
commands:
|
||||
- go generate ./...
|
||||
volumes:
|
||||
|
@ -26,21 +24,22 @@ steps:
|
|||
path: /go
|
||||
|
||||
- name: Validate
|
||||
image: docker.io/golang:1.20-alpine
|
||||
image: docker.io/golang:1.21-alpine
|
||||
network_mode: host
|
||||
privileged: true
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
GOPRIVATE: "code.icb4dc0.de/buildr/*"
|
||||
CGO_ENABLED: "0"
|
||||
DOCKER_HOST: tcp://localhost:2375
|
||||
BUILDR_VAULT_PASSPHRASE:
|
||||
from_secret: vault_password
|
||||
depends_on:
|
||||
- Generate protobuf files
|
||||
- Go generate
|
||||
commands:
|
||||
- apk add -U --no-cache fuse
|
||||
- CGO_ENABLED=0 go install -a -installsuffix=cgo -trimpath -ldflags="-s -w" .
|
||||
- buildr --execution.log-to-stderr task buf_generate
|
||||
- go install -trimpath -ldflags="-s -w" .
|
||||
- buildr plugins update
|
||||
- buildr --execution.log-to-stderr task go_generate
|
||||
- buildr --execution.log-to-stderr task go_fmt
|
||||
- buildr --execution.log-to-stderr task golangci_lint
|
||||
|
@ -57,6 +56,10 @@ kind: pipeline
|
|||
type: docker
|
||||
name: housekeeping
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: arm64
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- cron
|
||||
|
@ -64,13 +67,8 @@ trigger:
|
|||
- housekeeping
|
||||
|
||||
steps:
|
||||
- name: Generate protobuf files
|
||||
image: bufbuild/buf
|
||||
commands:
|
||||
- buf generate
|
||||
|
||||
- name: Go generate
|
||||
image: docker.io/golang:1.20-alpine
|
||||
image: docker.io/golang:1.21-alpine
|
||||
commands:
|
||||
- go generate ./...
|
||||
volumes:
|
||||
|
@ -96,4 +94,4 @@ steps:
|
|||
|
||||
volumes:
|
||||
- name: go-cache
|
||||
temp: { }
|
||||
temp: { }
|
||||
|
|
27
.editorconfig
Normal file
27
.editorconfig
Normal file
|
@ -0,0 +1,27 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
max_line_length = 120
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
ij_smart_tabs = true
|
||||
ij_go_GROUP_CURRENT_PROJECT_IMPORTS = true
|
||||
ij_go_group_stdlib_imports = true
|
||||
ij_go_import_sorting = goimports
|
||||
ij_go_local_group_mode = project
|
||||
ij_go_move_all_imports_in_one_declaration = true
|
||||
ij_go_move_all_stdlib_imports_in_one_group = true
|
||||
ij_go_remove_redundant_import_aliases = true
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
insert_final_newline = true
|
|
@ -1,7 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="new plugin" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||
<module name="buildr" />
|
||||
<working_directory value="$PROJECT_DIR$" />
|
||||
<working_directory value="$PROJECT_DIR$/buildr" />
|
||||
<parameters value="new task hello_world asdf" />
|
||||
<EXTENSION ID="net.ashald.envfile">
|
||||
<option name="IS_ENABLED" value="false" />
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="task go_fmt" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||
<module name="buildr" />
|
||||
<working_directory value="$PROJECT_DIR$" />
|
||||
<working_directory value="$PROJECT_DIR$/buildr" />
|
||||
<parameters value="--pprof.cpu-profile --pprof.out-file cpu.profile task go_fmt" />
|
||||
<EXTENSION ID="net.ashald.envfile">
|
||||
<option name="IS_ENABLED" value="false" />
|
||||
|
|
22
go.mod
22
go.mod
|
@ -3,27 +3,28 @@ module code.icb4dc0.de/buildr/buildr
|
|||
go 1.21
|
||||
|
||||
require (
|
||||
code.icb4dc0.de/buildr/api v0.0.0-20230817151157-dbc0adad8f8b
|
||||
code.icb4dc0.de/buildr/api v0.0.0-20230823165833-52d0bd9e9741
|
||||
code.icb4dc0.de/buildr/common v0.0.0-20230823164419-5a757074eaa3
|
||||
code.icb4dc0.de/prskr/go-pwgen v0.0.0-20230427131724-8ef26fd9749e
|
||||
entgo.io/ent v0.12.3
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/charmbracelet/bubbles v0.16.1
|
||||
github.com/charmbracelet/bubbletea v0.24.2
|
||||
github.com/charmbracelet/glamour v0.6.0
|
||||
github.com/charmbracelet/lipgloss v0.7.1
|
||||
github.com/charmbracelet/lipgloss v0.8.0
|
||||
github.com/docker/docker v24.0.5+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/go-git/go-git/v5 v5.8.1
|
||||
github.com/google/go-containerregistry v0.16.1
|
||||
github.com/google/go-github/v53 v53.2.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
github.com/hanwen/go-fuse/v2 v2.3.0
|
||||
github.com/hashicorp/go-getter v1.7.2
|
||||
github.com/hashicorp/hcl/v2 v2.17.0
|
||||
github.com/jinzhu/copier v0.3.5
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/klauspost/compress v1.16.7
|
||||
github.com/klauspost/pgzip v1.2.6
|
||||
github.com/muesli/termenv v0.15.2
|
||||
|
@ -34,7 +35,6 @@ require (
|
|||
github.com/tetratelabs/wazero v1.4.0
|
||||
github.com/zclconf/go-cty v1.13.2
|
||||
golang.org/x/crypto v0.12.0
|
||||
golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb
|
||||
golang.org/x/sync v0.3.0
|
||||
google.golang.org/grpc v1.57.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
|
@ -60,7 +60,7 @@ require (
|
|||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/alecthomas/chroma v0.10.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.325 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.329 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
|
@ -142,13 +142,13 @@ require (
|
|||
golang.org/x/term v0.11.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.12.0 // indirect
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/api v0.137.0 // indirect
|
||||
google.golang.org/api v0.138.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/uint128 v1.3.0 // indirect
|
||||
|
|
157
go.sum
157
go.sum
|
@ -1,5 +1,3 @@
|
|||
ariga.io/atlas v0.12.0 h1:jDfjxT3ppKhzqLS26lZv9ni7p9TVNrhy7SQquaF7bPs=
|
||||
ariga.io/atlas v0.12.0/go.mod h1:+TR129FJZ5Lvzms6dvCeGWh1yR6hMvmXBhug4hrNIGk=
|
||||
ariga.io/atlas v0.13.1 h1:oSkEYgI3qUnQZ6b6+teAEiIuizjBvkZ4YDbz0XWfCdQ=
|
||||
ariga.io/atlas v0.13.1/go.mod h1:+TR129FJZ5Lvzms6dvCeGWh1yR6hMvmXBhug4hrNIGk=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
|
@ -34,8 +32,6 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9
|
|||
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
|
||||
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
|
||||
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
|
||||
cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA=
|
||||
cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw=
|
||||
cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o=
|
||||
cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
|
||||
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
|
||||
|
@ -74,8 +70,6 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz
|
|||
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
|
||||
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||
cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
|
||||
cloud.google.com/go/compute v1.20.0 h1:cUOcywWuowO9It2i1KX1lIb0HH7gLv6nENKuZGnlcSo=
|
||||
cloud.google.com/go/compute v1.20.0/go.mod h1:kn5BhC++qUWR/AM3Dn21myV7QbgqejW04cAOrtppaQI=
|
||||
cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
|
||||
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
|
@ -117,8 +111,6 @@ cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y97
|
|||
cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
|
||||
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
|
||||
cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
|
||||
cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94=
|
||||
cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk=
|
||||
cloud.google.com/go/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4=
|
||||
cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU=
|
||||
cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
|
||||
|
@ -181,8 +173,6 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
|||
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||
cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
|
||||
cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
|
||||
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
|
||||
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
|
||||
cloud.google.com/go/storage v1.32.0 h1:5w6DxEGOnktmJHarxAOUywxVW9lbNWIzlzzUltG/3+o=
|
||||
cloud.google.com/go/storage v1.32.0/go.mod h1:Hhh/dogNRGca7IWv1RC2YqEn0c0G77ctA/OxflYkiD8=
|
||||
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
|
||||
|
@ -196,10 +186,10 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX
|
|||
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
|
||||
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
|
||||
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
|
||||
code.icb4dc0.de/buildr/api v0.0.0-20230816155529-748bd2ef327b h1:S7h+UltAjzuBQMlIkRk765DS5+Mq6G/nHWxOG7do/9U=
|
||||
code.icb4dc0.de/buildr/api v0.0.0-20230816155529-748bd2ef327b/go.mod h1:iI2z7GsD9jIb1Cnsn6Nu4Iu/f5iPDAJ7WkGefsZosfw=
|
||||
code.icb4dc0.de/buildr/api v0.0.0-20230817151157-dbc0adad8f8b h1:pZDHPJCMRw3UM1Jd0y7XnPZaDOzZ5du17EvW09mgb4g=
|
||||
code.icb4dc0.de/buildr/api v0.0.0-20230817151157-dbc0adad8f8b/go.mod h1:Bxt+fw/9hH7/WESz3asYBIWPr81UlUMEleXJGTqX6ys=
|
||||
code.icb4dc0.de/buildr/api v0.0.0-20230823165833-52d0bd9e9741 h1:uG2ECI+OT5oA5x2+G7upBhwKsYBS49xBIX+qlZrs9gw=
|
||||
code.icb4dc0.de/buildr/api v0.0.0-20230823165833-52d0bd9e9741/go.mod h1:eCeIvmMgYp/04nar7GnBDORMdO4jHYQl/RMiNJhyGf8=
|
||||
code.icb4dc0.de/buildr/common v0.0.0-20230823164419-5a757074eaa3 h1:jWQCCE56vhfNoOuJj4JlCEcfXUB/40iR8L59j5xeh+s=
|
||||
code.icb4dc0.de/buildr/common v0.0.0-20230823164419-5a757074eaa3/go.mod h1:u0PEZjq0l3ICCUgARZObM6Hc0ZlqkcjK0PBEozhAdNQ=
|
||||
code.icb4dc0.de/prskr/go-pwgen v0.0.0-20230427131724-8ef26fd9749e h1:N+3hdfeHRf/ndLjiZoet6h+9eZ2Zr5O/Ia5G7b3oQXU=
|
||||
code.icb4dc0.de/prskr/go-pwgen v0.0.0-20230427131724-8ef26fd9749e/go.mod h1:1MCCxqZsOgfQzV8AR2ZAVRI36MEGF+teFium6Pf2HHU=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
|
@ -210,13 +200,11 @@ entgo.io/ent v0.12.3/go.mod h1:AigGGx+tbrBBYHAzGOg8ND661E5cxx1Uiu5o/otJ6Yg=
|
|||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
|
@ -226,8 +214,6 @@ github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v
|
|||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 h1:JMDGhoQvXNTqH6Y3MC0IUw6tcZvaUdujNqzK2HYWZc8=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
||||
|
@ -244,12 +230,8 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkE
|
|||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go v1.44.280 h1:UYl/yxhDxP8naok6ftWyQ9/9ZzNwjC9dvEs/j8BkGhw=
|
||||
github.com/aws/aws-sdk-go v1.44.280/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.44.324 h1:/uja9PtgeeqrZCPOJTenjMLNpciIMuzaRKooq+erG4A=
|
||||
github.com/aws/aws-sdk-go v1.44.324/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.44.325 h1:jF/L99fJSq/BfiLmUOflO/aM+LwcqBm0Fe/qTK5xxuI=
|
||||
github.com/aws/aws-sdk-go v1.44.325/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.44.329 h1:Rqy+wYI8h+iq+FphR59KKTsHR1Lz7YiwRqFzWa7xoYU=
|
||||
github.com/aws/aws-sdk-go v1.44.329/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
|
@ -262,7 +244,6 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1U
|
|||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
|
@ -273,8 +254,8 @@ github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06
|
|||
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
|
||||
github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc=
|
||||
github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc=
|
||||
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
|
||||
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
|
||||
github.com/charmbracelet/lipgloss v0.8.0 h1:IS00fk4XAHcf8uZKc3eHeMUTCxUH6NkaTrdyCQk84RU=
|
||||
github.com/charmbracelet/lipgloss v0.8.0/go.mod h1:p4eYUZZJ/0oXTuCQKFF8mqyKCz0ja6y+7DniDDw5KKU=
|
||||
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
|
@ -303,18 +284,12 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
|
||||
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/docker/cli v24.0.2+incompatible h1:QdqR7znue1mtkXIJ+ruQMGQhpw2JzMJLRXp6zpzF6tM=
|
||||
github.com/docker/cli v24.0.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
|
||||
github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.2+incompatible h1:eATx+oLz9WdNVkQrr0qjQ8HvRJ4bOOxfzEo8R+dA3cg=
|
||||
github.com/docker/docker v24.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=
|
||||
github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
|
||||
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
|
@ -338,6 +313,8 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.
|
|||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
|
@ -349,8 +326,6 @@ github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8
|
|||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
|
||||
github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE=
|
||||
github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8=
|
||||
github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A=
|
||||
github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
|
@ -418,12 +393,8 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8
|
|||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE=
|
||||
github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q=
|
||||
github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ=
|
||||
github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
|
||||
github.com/google/go-github/v53 v53.0.0 h1:T1RyHbSnpHYnoF0ZYKiIPSgPtuJ8G6vgc0MKodXsQDQ=
|
||||
github.com/google/go-github/v53 v53.0.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao=
|
||||
github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI=
|
||||
github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
|
@ -452,19 +423,16 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe
|
|||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
|
||||
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
|
||||
github.com/google/s2a-go v0.1.5 h1:8IYp3w9nysqv3JH+NJgXJzGbDHzLOTj43BmSkp+O7qg=
|
||||
github.com/google/s2a-go v0.1.5/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.4 h1:uGy6JWR/uMIILU8wbf+OkstIrNiMjGpEIyhx8f6W7s4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
|
@ -476,8 +444,6 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99
|
|||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
|
||||
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
|
||||
github.com/googleapis/gax-go/v2 v2.10.0 h1:ebSgKfMxynOdxw8QQuFOKMgomqeLGPqNLQox2bo42zg=
|
||||
github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
|
@ -492,8 +458,6 @@ github.com/hanwen/go-fuse/v2 v2.3.0 h1:t5ivNIH2PK+zw4OBul/iJjsoG9K6kXo4nMDoBpciC
|
|||
github.com/hanwen/go-fuse/v2 v2.3.0/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY=
|
||||
github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
|
||||
github.com/hashicorp/go-getter v1.7.2 h1:uJDtyXwEfalmp1PqdxuhZqrNkUyClZAhVeZYTArbqkg=
|
||||
github.com/hashicorp/go-getter v1.7.2/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
|
@ -504,7 +468,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
|||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl/v2 v2.17.0 h1:z1XvSUyXd1HP10U4lrLg5e0JMVz6CPaJvAgxM0KNZVY=
|
||||
github.com/hashicorp/hcl/v2 v2.17.0/go.mod h1:gJyW2PTShkJqQBKpAmPO3yxMxIuoXkOF2TpqXzrQyx4=
|
||||
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
|
||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
|
||||
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
|
@ -517,8 +480,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
|
|||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
|
||||
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
|
@ -532,8 +495,6 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF
|
|||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
||||
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
|
@ -564,7 +525,6 @@ github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+Ei
|
|||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
|
@ -573,11 +533,8 @@ github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S
|
|||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
|
||||
github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw=
|
||||
github.com/microcosm-cc/bluemonday v1.0.24/go.mod h1:ArQySAMps0790cHSkdPEJ7bGkF2VePWH773hsJNSHf8=
|
||||
github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
|
||||
github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
|
@ -587,7 +544,6 @@ github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJ
|
|||
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
|
@ -604,8 +560,6 @@ github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIf
|
|||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
|
||||
github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs=
|
||||
github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=
|
||||
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
|
@ -613,8 +567,6 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N
|
|||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
|
@ -625,8 +577,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
|
||||
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
|
||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
|
@ -634,11 +584,8 @@ github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUo
|
|||
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
||||
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
|
@ -652,21 +599,16 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj
|
|||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE=
|
||||
github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
|
||||
github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM=
|
||||
github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||
|
@ -689,16 +631,11 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tetratelabs/wazero v1.2.0 h1:I/8LMf4YkCZ3r2XaL9whhA0VMyAvF6QE+O7rco0DCeQ=
|
||||
github.com/tetratelabs/wazero v1.2.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
|
||||
github.com/tetratelabs/wazero v1.4.0 h1:9/MirYvmkJ/zSUOygKY/ia3t+e+RqIZXKbylIby1WYk=
|
||||
github.com/tetratelabs/wazero v1.4.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
|
||||
github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck=
|
||||
github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY=
|
||||
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
|
||||
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
|
@ -711,13 +648,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
|||
github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU=
|
||||
github.com/yuin/goldmark v1.5.4/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.5.5 h1:IJznPe8wOzfIKETmMkd06F8nXkmlhaHqFRM9l1hAGsU=
|
||||
github.com/yuin/goldmark v1.5.5/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.5.6 h1:COmQAWTCcGetChm3Ig7G/t8AFAN00t+o8Mt4cf7JpwA=
|
||||
github.com/yuin/goldmark v1.5.6/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os=
|
||||
github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
|
||||
github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GAsO5s=
|
||||
github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY=
|
||||
|
@ -746,8 +678,6 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
|
|||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -760,9 +690,6 @@ 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-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-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U=
|
||||
golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA=
|
||||
golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
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/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -790,11 +717,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -822,8 +746,6 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri
|
|||
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
|
||||
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
|
||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||
golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
|
||||
golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -841,8 +763,6 @@ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -908,22 +828,17 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -938,8 +853,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -1003,10 +916,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
|
||||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
|
||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/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=
|
||||
|
@ -1064,10 +975,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ
|
|||
google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
|
||||
google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o=
|
||||
google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw=
|
||||
google.golang.org/api v0.137.0 h1:QrKX6uNvzJLr0Fd3vWVqcyrcmFoYi036VUAsZbiF4+s=
|
||||
google.golang.org/api v0.137.0/go.mod h1:4xyob8CxC+0GChNBvEUAk8VBKNvYOTWM9T3v3UfRxuY=
|
||||
google.golang.org/api v0.138.0 h1:K/tVp05MxNVbHShRw9m7e9VJGdagNeTdMzqPH7AUqr0=
|
||||
google.golang.org/api v0.138.0/go.mod h1:4xyob8CxC+0GChNBvEUAk8VBKNvYOTWM9T3v3UfRxuY=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
@ -1178,18 +1087,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw
|
|||
google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
|
||||
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
|
||||
google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
|
||||
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao=
|
||||
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
|
||||
google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878 h1:Iveh6tGCJkHAjJgEqUQYGDGgbwmhjoAOz8kO/ajxefY=
|
||||
google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878 h1:WGq4lvB/mlicysM/dUT3SBvijH4D3sm/Ny1A4wmt2CI=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 h1:lv6/DhyiFFGsmzxbsUUTOkN29II+zeWHxvT8Lpdxsv0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
@ -1225,8 +1128,6 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu
|
|||
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
|
||||
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
|
@ -1279,8 +1180,6 @@ lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
|
|||
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
|
||||
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
|
||||
modernc.org/ccgo/v3 v3.16.14 h1:af6KNtFgsVmnDYrWk3PQCS9XT6BXe7o3ZFJKkIKvXNQ=
|
||||
modernc.org/ccgo/v3 v3.16.14/go.mod h1:mPDSujUIaTNWQSG4eqKw+atqLOEbma6Ncsa94WbC9zo=
|
||||
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
|
||||
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
|
||||
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
||||
|
@ -1289,22 +1188,14 @@ modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
|||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||
modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM=
|
||||
modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o=
|
||||
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/memory v1.7.0 h1:2pXdbgdP5hIyDp2JqIwkHNZ1sAjEbh8GnRpcqFWBf7E=
|
||||
modernc.org/memory v1.7.0/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
|
||||
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
|
||||
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
|
||||
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
|
||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
|
||||
|
|
|
@ -97,7 +97,7 @@ type KnownModulesArgProvider interface {
|
|||
}
|
||||
|
||||
type ManCommander interface {
|
||||
DisplayModuleManual(pager Pager, cat modules.Category, name string) error
|
||||
DisplayModuleManual(ctx context.Context, pager Pager, cat modules.Category, name string) error
|
||||
DisplayModulesManual(pager Pager) error
|
||||
}
|
||||
|
||||
|
|
|
@ -194,17 +194,9 @@ func (a *App) Init(ctx context.Context) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
var db *state.DB
|
||||
if db, err = a.appCfg.InitState(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.Collection, err = services.NewCollection(
|
||||
services.WithTypeRegistry(registry),
|
||||
services.WithIgnorer(ignorer),
|
||||
services.WithDB(db),
|
||||
services.WithStateStore(db.State),
|
||||
services.WithCache(state.NewStateCache(a.appCfg.Cache.TTL, db.State)),
|
||||
services.WithDockerClientFromEnv(ctx),
|
||||
)
|
||||
|
||||
|
@ -281,15 +273,22 @@ func (a *App) RunModule(ctx context.Context, cat modules.Category, name string)
|
|||
})
|
||||
}
|
||||
|
||||
func (a *App) initBasic(context.Context) (err error) {
|
||||
func (a *App) initBasic(ctx context.Context) (err error) {
|
||||
var v *vault.Vault
|
||||
|
||||
if v, err = a.appCfg.InitVault(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var db *state.DB
|
||||
if db, err = a.appCfg.InitState(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return a.Collection.With(
|
||||
services.WithVault(v),
|
||||
services.WithDB(db),
|
||||
services.WithStateStore(db.State),
|
||||
services.WithCache(state.NewStateCache(a.appCfg.Cache.TTL, db.State)),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -318,7 +317,7 @@ func (a *App) initBuildRConfig(ctx context.Context) error {
|
|||
|
||||
_ = a.Collection.With(services.WithDiagnosticsWriter(parser.DiagsWriter()))
|
||||
|
||||
if err := buildrCfg.SetupDirectories(a.appCfg.BuildRDirectory, a.appCfg.RepoRoot); err != nil {
|
||||
if err := buildrCfg.SetupDirectories(a.appCfg.BuildRDirectory, a.appCfg.RepoRoot, a.appCfg.Execution.CleanDirectories); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"text/template"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
"log/slog"
|
||||
|
||||
v1 "code.icb4dc0.de/buildr/buildr/internal/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/tmpl"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/services"
|
||||
|
@ -48,7 +50,7 @@ type ManApp struct {
|
|||
serviceAccess ManAppServiceAccess
|
||||
}
|
||||
|
||||
func (m ManApp) DisplayModuleManual(pager Pager, cat modules.Category, name string) error {
|
||||
func (m ManApp) DisplayModuleManual(ctx context.Context, pager Pager, cat modules.Category, name string) error {
|
||||
mod, err := m.serviceAccess.TypeRegistry().Create(cat, name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -58,14 +60,14 @@ func (m ManApp) DisplayModuleManual(pager Pager, cat modules.Category, name stri
|
|||
if h, ok := mod.Unwrap().(modules.Helper); !ok {
|
||||
slog.Info(
|
||||
"Module has no help",
|
||||
slog.String("category", cat.String()),
|
||||
slog.String("category", v1.CategoryName(cat)),
|
||||
slog.String("name", name),
|
||||
)
|
||||
return nil
|
||||
} else if he, ok := h.Help(); ok {
|
||||
} else if he, err := h.Help(ctx); err == nil {
|
||||
help = he
|
||||
} else {
|
||||
return errors.New("module has no help")
|
||||
return fmt.Errorf("failed to get module help: %w", err)
|
||||
}
|
||||
|
||||
if err := m.templates.ExecuteTemplate(pager, "single-module-man.tmpl.md", help); err != nil {
|
||||
|
|
|
@ -2,11 +2,10 @@ package cmd
|
|||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/rpc"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/services"
|
||||
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
var _ ServerCommander = (*ServerApp)(nil)
|
||||
|
|
|
@ -5,13 +5,12 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"code.icb4dc0.de/prskr/go-pwgen"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/services"
|
||||
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
const defaultPassphraseFileMode os.FileMode = 0o600
|
||||
|
|
|
@ -39,7 +39,10 @@ type AppConfig struct {
|
|||
State struct{ FilePath string }
|
||||
Profiling profiling.Config
|
||||
Cache struct{ TTL time.Duration }
|
||||
Execution struct{ LogToStderr bool }
|
||||
Execution struct {
|
||||
LogToStderr bool
|
||||
CleanDirectories bool
|
||||
}
|
||||
}
|
||||
|
||||
func (c *AppConfig) CollectRepoDetails(vcsInfo any) (repoDetails repo.Repo, err error) {
|
||||
|
@ -100,6 +103,7 @@ func (c *AppConfig) InitPaths(from string) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
//nolint:nilnil // if state is empty we don't care
|
||||
func (c *AppConfig) InitState(ctx context.Context) (*state.DB, error) {
|
||||
if stateFilePath := c.State.FilePath; stateFilePath != "" {
|
||||
return state.NewDB(ctx, c.State.FilePath)
|
||||
|
@ -174,6 +178,13 @@ func (c *AppConfig) Flags() *flag.FlagSet {
|
|||
"If output of commands should be piped to stdout",
|
||||
)
|
||||
|
||||
flags.BoolVar(
|
||||
&c.Execution.CleanDirectories,
|
||||
"execution.clean-directories",
|
||||
config.EnvOr("BUILDR_EXECUTION_CLEAN_DIRECTORIES", strconv.ParseBool, false),
|
||||
"If ephemeral directories (currently out and logs) should be cleaned",
|
||||
)
|
||||
|
||||
flags.StringVar(
|
||||
&c.State.FilePath,
|
||||
"state.file-path",
|
||||
|
|
|
@ -75,6 +75,7 @@ func (m *ManConfig) Pager(ctx context.Context, title string) (Pager, error) {
|
|||
func ModuleManCommand(
|
||||
category modules.Category,
|
||||
cmder ManCommander,
|
||||
initializer LevelInitializer,
|
||||
argsProvider KnownModulesArgProvider,
|
||||
manCfg *ManConfig,
|
||||
) *cobra.Command {
|
||||
|
@ -86,12 +87,16 @@ func ModuleManCommand(
|
|||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: argsProvider.ValidModulesArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
p, err := manCfg.Pager(cmd.Context(), fmt.Sprintf("Manual - %s/%s", category.String(), args[0]))
|
||||
if err := initializer.InitAt(cmd.Context(), InitLevelBuildRConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p, err := manCfg.Pager(cmd.Context(), fmt.Sprintf("Manual - %s/%s", v1.CategoryName(category), args[0]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cmder.DisplayModuleManual(p, category, args[0])
|
||||
return cmder.DisplayModuleManual(cmd.Context(), p, category, args[0])
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +113,10 @@ func ManCmd(
|
|||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := initializer.InitAt(cmd.Context(), InitLevelBuildRConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p, err := manCfg.Pager(cmd.Context(), "Manual - modules")
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -120,6 +129,7 @@ func ManCmd(
|
|||
return ModuleManCommand(
|
||||
c,
|
||||
cmder,
|
||||
initializer,
|
||||
ModulesArgsProviderFor(initializer, registryAcc, c),
|
||||
&manCfg,
|
||||
)
|
||||
|
|
|
@ -6,12 +6,15 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func PluginListCommand(cmder PluginCommander) *cobra.Command {
|
||||
func PluginListCommand(cmder PluginCommander, initializer LevelInitializer) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List plugins",
|
||||
Aliases: []string{"ls", "dir"},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := initializer.InitAt(cmd.Context(), InitLevelBasic); err != nil {
|
||||
return err
|
||||
}
|
||||
return cmder.ListPlugins(cmd.Context(), os.Stdout)
|
||||
},
|
||||
}
|
||||
|
@ -42,7 +45,7 @@ func PluginsCommand(cmder PluginCommander, initializer LevelInitializer) *cobra.
|
|||
SilenceErrors: true,
|
||||
}
|
||||
|
||||
cmd.AddCommand(PluginListCommand(cmder), PluginUpdateCommand(cmder, initializer))
|
||||
cmd.AddCommand(PluginListCommand(cmder, initializer), PluginUpdateCommand(cmder, initializer))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"runtime"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
var CurrentVersion = "development"
|
||||
|
|
|
@ -9,9 +9,9 @@ import (
|
|||
const defaultDirectoryPermissions = 0o755
|
||||
|
||||
type PluginReference struct {
|
||||
Checksum *string `hcl:"checksum,optional"`
|
||||
Name string `hcl:",label"`
|
||||
URL string `hcl:"url"`
|
||||
Checksum *string `hcl:"checksum,optional"`
|
||||
}
|
||||
|
||||
type Buildr struct {
|
||||
|
@ -36,7 +36,7 @@ func (c Buildr) PluginURLs() (pluginUrls []*url.URL, err error) {
|
|||
return pluginUrls, nil
|
||||
}
|
||||
|
||||
func (c *Buildr) SetupDirectories(buildRDir, repoRoot string) error {
|
||||
func (c *Buildr) SetupDirectories(buildRDir, repoRoot string, cleanDirectories bool) error {
|
||||
if ucd, err := os.UserCacheDir(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
|
@ -63,7 +63,7 @@ func (c *Buildr) SetupDirectories(buildRDir, repoRoot string) error {
|
|||
c.OutDirectory = filepath.Join(repoRoot, c.OutDirectory)
|
||||
}
|
||||
|
||||
if err := createCleanDir(c.OutDirectory, true); err != nil {
|
||||
if err := createCleanDir(c.OutDirectory, cleanDirectories); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ func (c *Buildr) SetupDirectories(buildRDir, repoRoot string) error {
|
|||
c.LogsDirectory = filepath.Join(repoRoot, c.LogsDirectory)
|
||||
}
|
||||
|
||||
if err := createCleanDir(c.LogsDirectory, true); err != nil {
|
||||
if err := createCleanDir(c.LogsDirectory, cleanDirectories); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,9 @@ const defaultGRPCDialTimeout = 10 * time.Second
|
|||
var (
|
||||
_ Shutdowner = (*Orchestrator)(nil)
|
||||
architectureMapping = map[string]string{
|
||||
"amd64": "amd64",
|
||||
"x86_64": "amd64",
|
||||
"amd64": "amd64",
|
||||
"x86_64": "amd64",
|
||||
"aarch64": "arm64",
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -93,29 +94,9 @@ func (o *Orchestrator) BuildRContainer(ctx context.Context, spec *BuildRContaine
|
|||
|
||||
_, buildrExecutableName := filepath.Split(buildrExecutablePath)
|
||||
|
||||
containerRepoRoot := path.Join("/", "work", spec.ID)
|
||||
conSpec := ContainerSpec{
|
||||
Image: spec.Image,
|
||||
User: spec.User,
|
||||
Privileged: spec.Privileged,
|
||||
Capabilities: spec.Capabilities,
|
||||
ExposedPorts: []string{"3000/tcp"},
|
||||
Env: map[string]string{
|
||||
"BUILDR_GRPC_SERVE_ADDRESS": "0.0.0.0:3000",
|
||||
"BUILDR_REPO_ROOT": containerRepoRoot,
|
||||
"BUILDR_STATE_FILE_PATH": "/tmp/buildr.state",
|
||||
},
|
||||
Entrypoint: []string{
|
||||
path.Join("/opt/buildr/bin", buildrExecutableName),
|
||||
},
|
||||
Cmd: []string{
|
||||
"serve",
|
||||
"api",
|
||||
},
|
||||
Mounts: spec.Mounts,
|
||||
}
|
||||
containerRepoRoot, conSpec := spec.containerSpec(buildrExecutableName)
|
||||
|
||||
if err := o.createContainer(containerSetupCtx, &conSpec, con); err != nil {
|
||||
if err := o.createContainer(containerSetupCtx, conSpec, con); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
const containerAPICallingThreshold = 100 * time.Millisecond
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package containers
|
||||
|
||||
import "github.com/docker/docker/api/types/mount"
|
||||
import (
|
||||
"path"
|
||||
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
)
|
||||
|
||||
type Capabilities struct {
|
||||
Add []string
|
||||
|
@ -21,6 +25,32 @@ type BuildRContainerSpec struct {
|
|||
Privileged bool
|
||||
}
|
||||
|
||||
func (s *BuildRContainerSpec) containerSpec(buildrExecutableName string) (containerRepoRoot string, spec *ContainerSpec) {
|
||||
containerRepoRoot = path.Join("/", "work", s.ID)
|
||||
spec = &ContainerSpec{
|
||||
Image: s.Image,
|
||||
User: s.User,
|
||||
Privileged: s.Privileged,
|
||||
Capabilities: s.Capabilities,
|
||||
ExposedPorts: []string{"3000/tcp"},
|
||||
Env: map[string]string{
|
||||
"BUILDR_GRPC_SERVE_ADDRESS": "0.0.0.0:3000",
|
||||
"BUILDR_REPO_ROOT": containerRepoRoot,
|
||||
"BUILDR_STATE_FILE_PATH": "/tmp/buildr.state",
|
||||
},
|
||||
Entrypoint: []string{
|
||||
path.Join("/opt/buildr/bin", buildrExecutableName),
|
||||
},
|
||||
Cmd: []string{
|
||||
"serve",
|
||||
"api",
|
||||
},
|
||||
Mounts: s.Mounts,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type ContainerSpec struct {
|
||||
Env map[string]string
|
||||
Image string
|
||||
|
|
|
@ -13,13 +13,16 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"code.icb4dc0.de/buildr/common/protocol"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/errs"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/protocol"
|
||||
v1 "code.icb4dc0.de/buildr/buildr/internal/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
|
||||
"github.com/klauspost/compress/s2"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/containers"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/execution"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/ioutils"
|
||||
|
@ -65,7 +68,7 @@ func (c *containerTask) doExecute(ctx context.Context, spec execution.Spec) (err
|
|||
Default().
|
||||
With(
|
||||
slog.String("module_name", c.moduleWithMeta.Name()),
|
||||
slog.String("module_type", c.moduleWithMeta.Category().String()),
|
||||
slog.String("module_type", v1.CategoryName(c.moduleWithMeta.Category())),
|
||||
)
|
||||
|
||||
if c.moduleWithMeta.ShouldSkip() {
|
||||
|
|
|
@ -3,11 +3,10 @@ package local
|
|||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
|
||||
"log/slog"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/logging"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
v1 "code.icb4dc0.de/buildr/buildr/internal/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
@ -79,7 +80,7 @@ func (t *localTask) doExecute(ctx context.Context, spec execution.Spec) error {
|
|||
}
|
||||
|
||||
if err := t.module.Execute(execCtx); err != nil {
|
||||
return fmt.Errorf("failed to execute module %s/%s: %w", t.module.Category().String(), t.module.Name(), err)
|
||||
return fmt.Errorf("failed to execute module %s/%s: %w", v1.CategoryName(t.module.Category()), t.module.Name(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -149,7 +150,6 @@ func (t *localTask) executeIsolated(ctx context.Context, spec execution.Spec) er
|
|||
workDir,
|
||||
outDir,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ func (t *localTask) executeIsolated(ctx context.Context, spec execution.Spec) er
|
|||
}()
|
||||
|
||||
if err = t.module.Execute(execCtx); err != nil {
|
||||
return fmt.Errorf("failed to execute module %s/%s: %w", t.module.Category().String(), t.module.Name(), err)
|
||||
return fmt.Errorf("failed to execute module %s/%s: %w", v1.CategoryName(t.module.Category()), t.module.Name(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -186,7 +186,7 @@ func (t *localTask) executionContextFor(
|
|||
WithLoggerFactory(func() *slog.Logger {
|
||||
return slog.Default().With(
|
||||
slog.String("module_name", m.Name()),
|
||||
slog.String("module_type", m.Category().String()),
|
||||
slog.String("module_type", v1.CategoryName(m.Category())),
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
v1 "code.icb4dc0.de/buildr/buildr/internal/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
|
@ -15,7 +16,7 @@ func NewPlanFor(
|
|||
) (*Plan, error) {
|
||||
target := repo.Module(moduleType, moduleName)
|
||||
if target == nil {
|
||||
return nil, fmt.Errorf("%w: %s/%s", modules.ErrNoSuchModule, moduleType, moduleName)
|
||||
return nil, fmt.Errorf("%w: %s/%s", modules.ErrNoSuchModule, v1.CategoryName(moduleType), moduleName)
|
||||
}
|
||||
|
||||
entryPoint, err := factory.TaskForModule(target.ID(), repo)
|
||||
|
|
|
@ -123,8 +123,8 @@ func parsingSpecOf(modType modules.Category, block GenericBlock, additionalVaria
|
|||
}
|
||||
|
||||
type blockParsingSpec struct {
|
||||
Block GenericBlock
|
||||
AdditionalParsingVariables map[string]cty.Value
|
||||
Block GenericBlock
|
||||
Type modules.Category
|
||||
}
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ import (
|
|||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
type mappingCfg struct {
|
||||
type MappingCfg struct {
|
||||
MapAsObject bool
|
||||
StructAsMap bool
|
||||
}
|
||||
|
||||
//nolint:gocyclo // expected to be complex as entrypoint
|
||||
func mapToCtyVal(val any, cfg mappingCfg) (cty.Value, error) {
|
||||
func MapToCtyVal(val any, cfg MappingCfg) (cty.Value, error) {
|
||||
if val == nil {
|
||||
return cty.Value{}, nil
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ func mapToCtyVal(val any, cfg mappingCfg) (cty.Value, error) {
|
|||
case reflect.Float32, reflect.Float64:
|
||||
return cty.NumberFloatVal(value.Float()), nil
|
||||
case reflect.Pointer:
|
||||
return mapToCtyVal(reflect.ValueOf(val).Elem().Interface(), cfg)
|
||||
return MapToCtyVal(reflect.ValueOf(val).Elem().Interface(), cfg)
|
||||
case reflect.Map:
|
||||
return mapMap(t, value, cfg)
|
||||
case reflect.Slice, reflect.Array:
|
||||
|
@ -66,7 +66,7 @@ func mapToCtyVal(val any, cfg mappingCfg) (cty.Value, error) {
|
|||
out := make([]cty.Value, 0, length)
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
if mapped, err := mapToCtyVal(value.Index(i).Interface(), cfg); err != nil {
|
||||
if mapped, err := MapToCtyVal(value.Index(i).Interface(), cfg); err != nil {
|
||||
return cty.Value{}, err
|
||||
} else {
|
||||
out = append(out, mapped)
|
||||
|
@ -77,18 +77,18 @@ func mapToCtyVal(val any, cfg mappingCfg) (cty.Value, error) {
|
|||
case reflect.Struct:
|
||||
return mapStruct(t, value, cfg)
|
||||
default:
|
||||
return cty.Value{}, fmt.Errorf("unmapped type %s", t.Kind())
|
||||
return cty.NilVal, fmt.Errorf("unmapped type %s", t.Kind())
|
||||
}
|
||||
}
|
||||
|
||||
func mapStruct(t reflect.Type, val reflect.Value, cfg mappingCfg) (cty.Value, error) {
|
||||
func mapStruct(t reflect.Type, val reflect.Value, cfg MappingCfg) (cty.Value, error) {
|
||||
numField := t.NumField()
|
||||
out := make(map[string]cty.Value, numField)
|
||||
|
||||
for i := 0; i < numField; i++ {
|
||||
field := t.Field(i)
|
||||
if field.IsExported() && !isNil(val.Field(i)) {
|
||||
if mapped, err := mapToCtyVal(val.Field(i).Interface(), cfg); err != nil {
|
||||
if mapped, err := MapToCtyVal(val.Field(i).Interface(), cfg); err != nil {
|
||||
return cty.Value{}, err
|
||||
} else if field.Anonymous && mapped.CanIterateElements() {
|
||||
for key, val := range mapped.AsValueMap() {
|
||||
|
@ -114,7 +114,7 @@ func mapStruct(t reflect.Type, val reflect.Value, cfg mappingCfg) (cty.Value, er
|
|||
return cty.ObjectVal(out), nil
|
||||
}
|
||||
|
||||
func mapMap(t reflect.Type, val reflect.Value, cfg mappingCfg) (cty.Value, error) {
|
||||
func mapMap(t reflect.Type, val reflect.Value, cfg MappingCfg) (cty.Value, error) {
|
||||
if val.Len() == 0 {
|
||||
return cty.MapValEmpty(mapType(t.Elem())), nil
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func mapMap(t reflect.Type, val reflect.Value, cfg mappingCfg) (cty.Value, error
|
|||
|
||||
iter := val.MapRange()
|
||||
for iter.Next() {
|
||||
if mapped, err := mapToCtyVal(iter.Value().Interface(), cfg); err != nil {
|
||||
if mapped, err := MapToCtyVal(iter.Value().Interface(), cfg); err != nil {
|
||||
return cty.Value{}, err
|
||||
} else {
|
||||
out[iter.Key().String()] = mapped
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"reflect"
|
||||
|
||||
"github.com/hashicorp/hcl/v2/hclwrite"
|
||||
|
||||
"code.icb4dc0.de/buildr/common/hcl"
|
||||
)
|
||||
|
||||
func (w *Writer[T]) marshalInto(val reflect.Value, block *hclwrite.Block) error {
|
||||
|
@ -52,8 +54,8 @@ func (w *Writer[T]) marshalField(structField reflect.StructField, fieldVal refle
|
|||
return nil
|
||||
}
|
||||
|
||||
marshalCfg, err := marshalConfigOf(structField)
|
||||
if err != nil && !errors.Is(err, errNoHclTag) {
|
||||
marshalCfg, err := hcl.ExtractFieldMeta(structField, "hcl", "hcl_write")
|
||||
if err != nil && !errors.Is(err, hcl.ErrNoHclTag) {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -61,7 +63,7 @@ func (w *Writer[T]) marshalField(structField reflect.StructField, fieldVal refle
|
|||
return nil
|
||||
}
|
||||
|
||||
handleStruct := func(val reflect.Value, t elementType, name string) error {
|
||||
handleStruct := func(val reflect.Value, t hcl.ElementType, name string) error {
|
||||
var (
|
||||
targetBlock *hclwrite.Block
|
||||
needsAppending bool
|
||||
|
@ -69,10 +71,10 @@ func (w *Writer[T]) marshalField(structField reflect.StructField, fieldVal refle
|
|||
|
||||
//nolint:exhaustive // not necessary here
|
||||
switch t {
|
||||
case elementTypeBlock:
|
||||
case hcl.ElementTypeBlock:
|
||||
targetBlock = hclwrite.NewBlock(name, discoverLabels(val.Type()))
|
||||
needsAppending = true
|
||||
case elementTypeRemain:
|
||||
case hcl.ElementTypeRemain:
|
||||
targetBlock = block
|
||||
default:
|
||||
return fmt.Errorf("undefined block creation behavior for type %s", marshalCfg.Type)
|
||||
|
@ -92,22 +94,22 @@ func (w *Writer[T]) marshalField(structField reflect.StructField, fieldVal refle
|
|||
switch fieldVal.Kind() {
|
||||
case reflect.Map:
|
||||
if isPrimitiveType(fieldVal.Type().Elem()) {
|
||||
if v, err := mapToCtyVal(fieldVal, mappingCfg{}); err != nil {
|
||||
if v, err := MapToCtyVal(fieldVal, MappingCfg{}); err != nil {
|
||||
return err
|
||||
} else {
|
||||
block.Body().SetAttributeValue(marshalCfg.Name, v)
|
||||
}
|
||||
}
|
||||
case reflect.Slice, reflect.Array:
|
||||
if isPrimitiveType(fieldVal.Type().Elem()) || marshalCfg.Type == elementTypeAttribute {
|
||||
if v, err := mapToCtyVal(fieldVal, mappingCfg{}); err != nil {
|
||||
if isPrimitiveType(fieldVal.Type().Elem()) || marshalCfg.Type == hcl.ElementTypeAttribute {
|
||||
if v, err := MapToCtyVal(fieldVal, MappingCfg{}); err != nil {
|
||||
return err
|
||||
} else {
|
||||
block.Body().SetAttributeValue(marshalCfg.Name, v)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < fieldVal.Len(); i++ {
|
||||
if err := handleStruct(fieldVal.Index(i), elementTypeBlock, marshalCfg.Name); err != nil {
|
||||
if err := handleStruct(fieldVal.Index(i), hcl.ElementTypeBlock, marshalCfg.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -119,18 +121,18 @@ func (w *Writer[T]) marshalField(structField reflect.StructField, fieldVal refle
|
|||
|
||||
return w.marshalField(structField, fieldVal.Elem(), block)
|
||||
case reflect.Struct:
|
||||
if marshalCfg.Type != elementTypeBlock && marshalCfg.Type != elementTypeRemain {
|
||||
if marshalCfg.Type != hcl.ElementTypeBlock && marshalCfg.Type != hcl.ElementTypeRemain {
|
||||
return fmt.Errorf("field %s is a struct but not marked as block", structField.Name)
|
||||
}
|
||||
|
||||
return handleStruct(fieldVal, marshalCfg.Type, marshalCfg.Name)
|
||||
default:
|
||||
if val, err := mapToCtyVal(fieldVal, mappingCfg{}); err == nil {
|
||||
if val, err := MapToCtyVal(fieldVal, MappingCfg{}); err == nil {
|
||||
//nolint:exhaustive // not necessary here
|
||||
switch marshalCfg.Type {
|
||||
case elementTypeAttribute:
|
||||
case hcl.ElementTypeAttribute:
|
||||
block.Body().SetAttributeValue(marshalCfg.Name, val)
|
||||
case elementTypeLabel:
|
||||
case hcl.ElementTypeLabel:
|
||||
block.SetLabels(append(block.Labels(), val.AsString()))
|
||||
}
|
||||
}
|
||||
|
@ -148,12 +150,12 @@ func discoverLabels(t reflect.Type) []string {
|
|||
continue
|
||||
}
|
||||
|
||||
marshalCfg, err := marshalConfigOf(structField)
|
||||
if err != nil && !errors.Is(err, errNoHclTag) {
|
||||
marshalCfg, err := hcl.ExtractFieldMeta(structField, "hcl", "hcl_write")
|
||||
if err != nil && !errors.Is(err, hcl.ErrNoHclTag) {
|
||||
continue
|
||||
}
|
||||
|
||||
if marshalCfg.Type == elementTypeLabel {
|
||||
if marshalCfg.Type == hcl.ElementTypeLabel {
|
||||
labels = append(labels, marshalCfg.Name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
package hcl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
elementTypeAttribute elementType = "attr"
|
||||
elementTypeBlock elementType = "block"
|
||||
elementTypeLabel elementType = "label"
|
||||
elementTypeRemain elementType = "remain"
|
||||
)
|
||||
|
||||
var errNoHclTag = errors.New("no hcl tag")
|
||||
|
||||
type elementType string
|
||||
|
||||
func marshalConfigOf(t reflect.StructField) (marshalConfig, error) {
|
||||
hclTag, present := t.Tag.Lookup("hcl")
|
||||
if !present {
|
||||
return marshalConfig{}, errNoHclTag
|
||||
}
|
||||
|
||||
cfg := marshalConfig{
|
||||
Name: t.Name,
|
||||
Type: elementTypeAttribute,
|
||||
}
|
||||
|
||||
if hclWriteTag, present := t.Tag.Lookup("hcl_write"); present && hclWriteTag == "-" {
|
||||
cfg.Ignore = true
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
split := strings.Split(hclTag, ",")
|
||||
|
||||
if len(split) > 0 && split[0] != "" {
|
||||
cfg.Name = split[0]
|
||||
}
|
||||
|
||||
if len(split) > 1 {
|
||||
switch split[1] {
|
||||
case "":
|
||||
fallthrough
|
||||
case "attr":
|
||||
cfg.Type = elementTypeAttribute
|
||||
case "optional":
|
||||
cfg.Optional = true
|
||||
case "label":
|
||||
cfg.Type = elementTypeLabel
|
||||
case "block":
|
||||
cfg.Type = elementTypeBlock
|
||||
case "remain":
|
||||
cfg.Type = elementTypeRemain
|
||||
default:
|
||||
return marshalConfig{}, fmt.Errorf("unknown element type %q", split[1])
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
type marshalConfig struct {
|
||||
Name string
|
||||
Type elementType
|
||||
Optional bool
|
||||
Ignore bool
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/hcl/v2/hclwrite"
|
||||
|
||||
v1 "code.icb4dc0.de/buildr/buildr/internal/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
|
@ -39,7 +40,7 @@ type Writer[T modules.ModuleWithMeta] struct {
|
|||
func (w *Writer[T]) Write(in T) error {
|
||||
f := hclwrite.NewEmptyFile()
|
||||
|
||||
block := hclwrite.NewBlock(in.Category().String(), []string{in.Type(), in.Name()})
|
||||
block := hclwrite.NewBlock(v1.CategoryName(in.Category()), []string{in.Type(), in.Name()})
|
||||
if err := w.marshalInto(reflect.ValueOf(in), block); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
func Diagnostics(diag hcl.Diagnostics, logger *slog.Logger) {
|
||||
if !diag.HasErrors() {
|
||||
return
|
||||
}
|
||||
|
||||
if logger == nil {
|
||||
logger = slog.Default()
|
||||
}
|
||||
|
||||
for _, d := range diag {
|
||||
var level slog.Level
|
||||
switch d.Severity {
|
||||
case hcl.DiagInvalid, hcl.DiagError:
|
||||
level = slog.LevelError
|
||||
case hcl.DiagWarning:
|
||||
level = slog.LevelWarn
|
||||
default:
|
||||
level = slog.LevelInfo
|
||||
}
|
||||
|
||||
logArgs := []any{
|
||||
slog.String("detail", strings.ReplaceAll(d.Detail, "\"", "'")),
|
||||
}
|
||||
|
||||
if d.Context != nil {
|
||||
logArgs = append(logArgs,
|
||||
slog.String("filename", d.Context.Filename),
|
||||
slog.Int("start_line", d.Context.Start.Line),
|
||||
slog.Int("start_column", d.Context.Start.Line),
|
||||
slog.Int("end_line", d.Context.End.Line),
|
||||
slog.Int("end_column", d.Context.End.Line),
|
||||
)
|
||||
}
|
||||
|
||||
logger.Log(
|
||||
context.Background(),
|
||||
level,
|
||||
d.Summary,
|
||||
logArgs...,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -2,9 +2,8 @@ package logging
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"log/slog"
|
||||
"os"
|
||||
)
|
||||
|
||||
func NewConfig() Config {
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/config"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/slices"
|
||||
|
@ -26,12 +25,12 @@ import (
|
|||
"code.icb4dc0.de/buildr/buildr/modules/plugin"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
Downloader Downloader
|
||||
lock sync.RWMutex
|
||||
plugins state.Plugins
|
||||
cacheDir string
|
||||
}
|
||||
|
@ -59,13 +58,25 @@ func (p *Manager) Register(ctx context.Context, registry *modules.TypeRegistry)
|
|||
for _, module := range knownModules {
|
||||
module := module
|
||||
registry.RegisterModule(modules.ModuleFactoryFunc(func() modules.ModuleWithMeta {
|
||||
return &modules.Metadata[plugin.Module]{
|
||||
Module: plugin.Module{
|
||||
PluginPayload: &plugin.PayloadFile{Path: registeredPlugin.LocalPath},
|
||||
var (
|
||||
defaultSpec = new(rpcv1.ModuleSpec)
|
||||
mod = plugin.Module{
|
||||
PluginPayload: &plugin.PayloadFile{
|
||||
Path: registeredPlugin.LocalPath,
|
||||
Checksum: registeredPlugin.Hash,
|
||||
},
|
||||
PluginCategory: module.Category,
|
||||
PluginType: module.Type,
|
||||
ModuleSpec: make(map[string]any),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if err := defaultSpec.UnmarshalVT(module.DefaultSpec); err == nil {
|
||||
mod.SetModuleSpec(defaultSpec)
|
||||
}
|
||||
|
||||
return &modules.Metadata[plugin.Module]{
|
||||
Module: mod,
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
@ -108,7 +119,7 @@ func (p *Manager) UpdatePlugins(ctx context.Context, refs ...config.PluginRefere
|
|||
} else if inventory, err := plugin.DiscoverInventory(ctx, payload); err != nil {
|
||||
return err
|
||||
} else {
|
||||
pluginModules := slices.Map(inventory.Modules, func(in *rpcv1.ModuleReference) state.PluginModule {
|
||||
pluginModules := slices.Map(inventory.Specs, func(in *rpcv1.PluginInventory_InventorySpec) state.PluginModule {
|
||||
return moduleReferenceToPluginModule(pluginID, in)
|
||||
})
|
||||
if err := p.plugins.UpsertModules(ctx, pluginModules); err != nil {
|
||||
|
@ -209,17 +220,20 @@ func (p *Manager) validateKnownPlugin(knownPlugin state.Plugin, ref config.Plugi
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func validateHashForFile(filePath string, hash []byte) (computedHash []byte, equal bool, err error) {
|
||||
func validateHashForFile(filePath string, expectedHash []byte) (computedHash []byte, equal bool, err error) {
|
||||
computedHash, _, err = hashFile(filePath, sha256.New())
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
if !bytes.Equal(hash, computedHash) {
|
||||
if !bytes.Equal(expectedHash, computedHash) {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
return computedHash, true, nil
|
||||
}
|
||||
|
||||
func hashFile(filePath string, h hash.Hash) (hash []byte, payload []byte, err error) {
|
||||
func hashFile(filePath string, h hash.Hash) (computedHash, payload []byte, err error) {
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -239,10 +253,11 @@ func hashFile(filePath string, h hash.Hash) (hash []byte, payload []byte, err er
|
|||
return h.Sum(nil), buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func moduleReferenceToPluginModule(pluginID uuid.UUID, in *rpcv1.ModuleReference) state.PluginModule {
|
||||
func moduleReferenceToPluginModule(pluginID uuid.UUID, in *rpcv1.PluginInventory_InventorySpec) state.PluginModule {
|
||||
return state.PluginModule{
|
||||
PluginID: pluginID,
|
||||
Type: in.ModuleType,
|
||||
Category: in.ModuleCategory,
|
||||
PluginID: pluginID,
|
||||
Type: in.ModuleRef.ModuleType,
|
||||
Category: in.ModuleRef.ModuleCategory,
|
||||
DefaultSpec: in.EmptySpec,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
package plugins_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules/plugin"
|
||||
)
|
||||
|
||||
func TestPluginModule_UnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
type args struct {
|
||||
data []byte
|
||||
}
|
||||
tests := []struct {
|
||||
want func(m *plugin.Module) error
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Empty json",
|
||||
args: args{
|
||||
data: []byte(`{}`),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Set type and category",
|
||||
args: args{
|
||||
data: []byte(`{"plugin_type": "test", "plugin_category": "task"}`),
|
||||
},
|
||||
want: func(m *plugin.Module) error {
|
||||
if m.PluginCategory == "" {
|
||||
return errors.New("category is empty")
|
||||
}
|
||||
|
||||
if m.PluginType == "" {
|
||||
return errors.New("type is empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var m plugin.Module
|
||||
if err := m.UnmarshalJSON(tt.args.data); (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
if tt.want != nil {
|
||||
if err := tt.want(&m); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package protocol
|
||||
|
||||
import rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
type SpecUnmarshaler interface {
|
||||
UnmarshalModuleSpec(val *rpcv1.ModuleSpec) error
|
||||
}
|
||||
|
||||
type SpecValueUnmarshaler interface {
|
||||
UnmarshalSpecValue(val *rpcv1.ModuleSpec_Value) error
|
||||
}
|
|
@ -1,238 +0,0 @@
|
|||
package protocol
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
)
|
||||
|
||||
var ErrExpectedStruct = errors.New("expected struct")
|
||||
|
||||
func Marshal(in any) (*rpcv1.ModuleSpec, error) {
|
||||
cfg := marshalConfig{
|
||||
TagName: "hcl",
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(in)
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("%w: got %T", ErrExpectedStruct, in)
|
||||
}
|
||||
|
||||
return cfg.marshal(val)
|
||||
}
|
||||
|
||||
type marshalConfig struct {
|
||||
TagName string
|
||||
}
|
||||
|
||||
func (cfg marshalConfig) marshal(in reflect.Value) (*rpcv1.ModuleSpec, error) {
|
||||
numField := in.NumField()
|
||||
|
||||
out := &rpcv1.ModuleSpec{
|
||||
Values: make(map[string]*rpcv1.ModuleSpec_Value, numField),
|
||||
}
|
||||
|
||||
// TODO consider tag for field name
|
||||
|
||||
inputType := in.Type()
|
||||
|
||||
for i := 0; i < numField; i++ {
|
||||
structField := inputType.Field(i)
|
||||
if !structField.IsExported() {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldName := cfg.fieldName(structField)
|
||||
|
||||
out.Values[fieldName] = cfg.mapReflectValueToSpecValue(in.Field(i))
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (cfg marshalConfig) mapReflectValueToSpecValue(in reflect.Value) *rpcv1.ModuleSpec_Value {
|
||||
switch in.Kind() {
|
||||
case reflect.Map:
|
||||
return cfg.mapValue(in)
|
||||
case reflect.Bool:
|
||||
return boolValue(in.Bool())
|
||||
case reflect.String:
|
||||
return stringValue(in.String())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return intValue(in.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return intValue(in.Uint())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return floatValue(in.Float())
|
||||
case reflect.Struct:
|
||||
return cfg.structValue(in)
|
||||
case reflect.Slice, reflect.Array:
|
||||
switch in.Type().Elem().Kind() {
|
||||
case reflect.Bool:
|
||||
return boolSliceValue(in)
|
||||
case reflect.String:
|
||||
return stringSliceValue(in)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return intSliceValue(in, reflect.Value.Int)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return intSliceValue(in, func(v reflect.Value) int64 {
|
||||
return int64(v.Uint())
|
||||
})
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return floatSliceValue(in)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg marshalConfig) fieldName(field reflect.StructField) string {
|
||||
tagVal, ok := field.Tag.Lookup(cfg.TagName)
|
||||
if !ok {
|
||||
return field.Name
|
||||
}
|
||||
|
||||
split := strings.Split(tagVal, ",")
|
||||
|
||||
switch {
|
||||
case len(split) == 0:
|
||||
fallthrough
|
||||
case split[0] == "":
|
||||
return strings.ToLower(field.Name)
|
||||
default:
|
||||
return strings.ToLower(split[0])
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg marshalConfig) mapValue(in reflect.Value) *rpcv1.ModuleSpec_Value {
|
||||
result := &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeMap,
|
||||
ComplexValue: make(map[string]*rpcv1.ModuleSpec_Value, in.Len()),
|
||||
}
|
||||
|
||||
iter := in.MapRange()
|
||||
for iter.Next() {
|
||||
result.ComplexValue[iter.Key().String()] = cfg.mapReflectValueToSpecValue(iter.Value())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (cfg marshalConfig) structValue(in reflect.Value) *rpcv1.ModuleSpec_Value {
|
||||
inputType := in.Type()
|
||||
numFields := inputType.NumField()
|
||||
result := &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeObject,
|
||||
ComplexValue: make(map[string]*rpcv1.ModuleSpec_Value, numFields),
|
||||
}
|
||||
|
||||
for i := 0; i < numFields; i++ {
|
||||
structField := inputType.Field(i)
|
||||
if !structField.IsExported() {
|
||||
continue
|
||||
}
|
||||
|
||||
result.ComplexValue[structField.Name] = cfg.mapReflectValueToSpecValue(in.Field(i))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func boolValue(in bool) *rpcv1.ModuleSpec_Value {
|
||||
return &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_BoolValue{
|
||||
BoolValue: in,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func boolSliceValue(val reflect.Value) *rpcv1.ModuleSpec_Value {
|
||||
result := &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeBoolSlice,
|
||||
BoolValues: make([]bool, 0, val.Len()),
|
||||
}
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
result.BoolValues = append(result.BoolValues, val.Index(i).Bool())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func intValue[T constraints.Integer](in T) *rpcv1.ModuleSpec_Value {
|
||||
return &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_IntValue{
|
||||
IntValue: int64(in),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func intSliceValue(val reflect.Value, selector func(v reflect.Value) int64) *rpcv1.ModuleSpec_Value {
|
||||
result := &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeIntSlice,
|
||||
IntValues: make([]int64, 0, val.Len()),
|
||||
}
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
result.IntValues = append(result.IntValues, selector(val.Index(i)))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func floatValue[T constraints.Float](in T) *rpcv1.ModuleSpec_Value {
|
||||
return &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_DoubleValue{
|
||||
DoubleValue: float64(in),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func floatSliceValue(val reflect.Value) *rpcv1.ModuleSpec_Value {
|
||||
result := &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeDoubleSlice,
|
||||
DoubleValues: make([]float64, 0, val.Len()),
|
||||
}
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
result.DoubleValues = append(result.DoubleValues, val.Index(i).Float())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func stringValue(in string) *rpcv1.ModuleSpec_Value {
|
||||
return &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_StringValue{
|
||||
StringValue: in,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func stringSliceValue(val reflect.Value) *rpcv1.ModuleSpec_Value {
|
||||
result := &rpcv1.ModuleSpec_Value{
|
||||
Type: rpcv1.ModuleSpec_ValueTypeStringSlice,
|
||||
StringValues: make([]string, 0, val.Len()),
|
||||
}
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
result.StringValues = append(result.StringValues, val.Index(i).String())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
package protocol_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/protocol"
|
||||
)
|
||||
|
||||
func TestMarshal_Bool_Success(t *testing.T) {
|
||||
input := struct {
|
||||
IsDeleted bool
|
||||
}{
|
||||
IsDeleted: true,
|
||||
}
|
||||
|
||||
spec, err := protocol.Marshal(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nameVal, ok := spec.Values["IsDeleted"]
|
||||
if !ok {
|
||||
t.Fatal("IsDeleted not found")
|
||||
}
|
||||
|
||||
if nameVal.Type != rpcv1.ModuleSpec_ValueTypeSingle {
|
||||
t.Fatalf("Expected single value type, got %v", nameVal.Type)
|
||||
}
|
||||
|
||||
if s, ok := nameVal.SingleValue.(*rpcv1.ModuleSpec_Value_BoolValue); !ok {
|
||||
t.Fatalf("Expected string value, got %v", nameVal.SingleValue)
|
||||
} else if !s.BoolValue {
|
||||
t.Errorf("Expected bool value to be true, got %t", s.BoolValue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshal_BoolSlice_Success(t *testing.T) {
|
||||
input := struct {
|
||||
IsDeleted []bool
|
||||
}{
|
||||
IsDeleted: []bool{true},
|
||||
}
|
||||
|
||||
spec, err := protocol.Marshal(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nameVal, ok := spec.Values["IsDeleted"]
|
||||
if !ok {
|
||||
t.Fatal("IsDeleted not found")
|
||||
}
|
||||
|
||||
if nameVal.Type != rpcv1.ModuleSpec_ValueTypeBoolSlice {
|
||||
t.Fatalf("Expected bool slice value type, got %v", nameVal.Type)
|
||||
}
|
||||
|
||||
if len(nameVal.BoolValues) < 1 {
|
||||
t.Fatalf("Expected at least one bool value, got %d", len(nameVal.BoolValues))
|
||||
}
|
||||
|
||||
if !nameVal.BoolValues[0] {
|
||||
t.Errorf("Expected bool value to be true, got %t", nameVal.BoolValues[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshal_Int_Success(t *testing.T) {
|
||||
input := struct {
|
||||
Age int
|
||||
}{
|
||||
Age: 42,
|
||||
}
|
||||
|
||||
spec, err := protocol.Marshal(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nameVal, ok := spec.Values["Age"]
|
||||
if !ok {
|
||||
t.Fatal("Age not found")
|
||||
}
|
||||
|
||||
if nameVal.Type != rpcv1.ModuleSpec_ValueTypeSingle {
|
||||
t.Fatalf("Expected single value type, got %v", nameVal.Type)
|
||||
}
|
||||
|
||||
if s, ok := nameVal.SingleValue.(*rpcv1.ModuleSpec_Value_IntValue); !ok {
|
||||
t.Fatalf("Expected string value, got %v", nameVal.SingleValue)
|
||||
} else if s.IntValue != 42 {
|
||||
t.Errorf("Expected int value to be 42, got %d", s.IntValue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshal_IntSlice_Success(t *testing.T) {
|
||||
input := struct {
|
||||
Ages []int
|
||||
}{
|
||||
Ages: []int{42},
|
||||
}
|
||||
|
||||
spec, err := protocol.Marshal(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nameVal, ok := spec.Values["Ages"]
|
||||
if !ok {
|
||||
t.Fatal("Ages not found")
|
||||
}
|
||||
|
||||
if nameVal.Type != rpcv1.ModuleSpec_ValueTypeIntSlice {
|
||||
t.Fatalf("Expected int slice value type, got %v", nameVal.Type)
|
||||
}
|
||||
|
||||
if len(nameVal.IntValues) < 1 {
|
||||
t.Fatalf("Expected at least one bool value, got %d", len(nameVal.BoolValues))
|
||||
}
|
||||
|
||||
if nameVal.IntValues[0] != 42 {
|
||||
t.Errorf("Expected int value to be 52, got %d", nameVal.IntValues[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshal_StringField_Success(t *testing.T) {
|
||||
input := struct {
|
||||
Name string
|
||||
}{
|
||||
Name: "John Doe",
|
||||
}
|
||||
|
||||
spec, err := protocol.Marshal(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nameVal, ok := spec.Values["Name"]
|
||||
if !ok {
|
||||
t.Fatal("Name not found")
|
||||
}
|
||||
|
||||
if nameVal.Type != rpcv1.ModuleSpec_ValueTypeSingle {
|
||||
t.Fatalf("Expected single value type, got %v", nameVal.Type)
|
||||
}
|
||||
|
||||
if s, ok := nameVal.SingleValue.(*rpcv1.ModuleSpec_Value_StringValue); !ok {
|
||||
t.Fatalf("Expected string value, got %v", nameVal.SingleValue)
|
||||
} else if s.StringValue != "John Doe" {
|
||||
t.Errorf("Expected string value to be John Doe, got %s", s.StringValue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshal_Float64_Success(t *testing.T) {
|
||||
input := struct {
|
||||
Pi float64
|
||||
}{
|
||||
Pi: 3.14,
|
||||
}
|
||||
|
||||
spec, err := protocol.Marshal(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nameVal, ok := spec.Values["Pi"]
|
||||
if !ok {
|
||||
t.Fatal("Pi not found")
|
||||
}
|
||||
|
||||
if nameVal.Type != rpcv1.ModuleSpec_ValueTypeSingle {
|
||||
t.Fatalf("Expected single value type, got %v", nameVal.Type)
|
||||
}
|
||||
|
||||
if s, ok := nameVal.SingleValue.(*rpcv1.ModuleSpec_Value_DoubleValue); !ok {
|
||||
t.Fatalf("Expected double value, got %v", nameVal.SingleValue)
|
||||
} else if s.DoubleValue-3.14 > 0.000001 {
|
||||
t.Errorf("Expected double value to be 3.14, got %f", s.DoubleValue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshal_NestedStruct_Success(t *testing.T) {
|
||||
type Address struct {
|
||||
City string
|
||||
}
|
||||
input := struct {
|
||||
Address Address
|
||||
}{
|
||||
Address: Address{
|
||||
City: "New York",
|
||||
},
|
||||
}
|
||||
|
||||
spec, err := protocol.Marshal(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addressVal, ok := spec.Values["Address"]
|
||||
if !ok {
|
||||
t.Fatal("Address not found")
|
||||
}
|
||||
|
||||
if addressVal.Type != rpcv1.ModuleSpec_ValueTypeObject {
|
||||
t.Fatalf("Expected object value type, got %v", addressVal.Type)
|
||||
}
|
||||
|
||||
cityVal, ok := addressVal.ComplexValue["City"]
|
||||
if !ok {
|
||||
t.Fatal("City not found")
|
||||
}
|
||||
|
||||
if cityVal.Type != rpcv1.ModuleSpec_ValueTypeSingle {
|
||||
t.Fatalf("Expected single value type, got %v", cityVal.Type)
|
||||
}
|
||||
|
||||
if cityVal.SingleValue.(*rpcv1.ModuleSpec_Value_StringValue).StringValue != "New York" {
|
||||
t.Errorf("Expected string value to be New York, got %s", cityVal.SingleValue.(*rpcv1.ModuleSpec_Value_StringValue).StringValue)
|
||||
}
|
||||
}
|
|
@ -1,195 +0,0 @@
|
|||
package protocol
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnmatchingType = errors.New("field type does not match wire value")
|
||||
)
|
||||
|
||||
func Unmarshal(input *rpcv1.ModuleSpec, into any) error {
|
||||
|
||||
if u, ok := into.(SpecUnmarshaler); ok {
|
||||
return u.UnmarshalModuleSpec(input)
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(into)
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Ptr:
|
||||
default:
|
||||
return errors.New("into value must be a pointer")
|
||||
}
|
||||
return unmarshal(input.Values, val.Elem(), reflect.TypeOf(into).Elem())
|
||||
}
|
||||
|
||||
func unmarshal(input map[string]*rpcv1.ModuleSpec_Value, into reflect.Value, intoType reflect.Type) error {
|
||||
for i := 0; i < intoType.NumField(); i++ {
|
||||
tf := intoType.Field(i)
|
||||
if !tf.IsExported() {
|
||||
continue
|
||||
}
|
||||
|
||||
val, ok := input[strings.ToLower(tf.Name)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if into.Type().Kind() == reflect.Pointer {
|
||||
if u, ok := into.Elem().Field(i).Interface().(SpecValueUnmarshaler); ok {
|
||||
if err := u.UnmarshalSpecValue(val); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if u, ok := into.Field(i).Interface().(SpecValueUnmarshaler); ok {
|
||||
if err := u.UnmarshalSpecValue(val); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if mapped, err := mapSpecValueTo(val, tf.Type); err != nil {
|
||||
return err
|
||||
} else if into.Type().Kind() == reflect.Pointer {
|
||||
into.Elem().Field(i).Set(mapped)
|
||||
} else {
|
||||
into.Field(i).Set(mapped)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mapSpecValueTo(val *rpcv1.ModuleSpec_Value, targetType reflect.Type) (reflect.Value, error) {
|
||||
switch val.Type {
|
||||
case rpcv1.ModuleSpec_ValueTypeUnknown:
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected %s", ErrUnmatchingType, targetType.String())
|
||||
case rpcv1.ModuleSpec_ValueTypeObject:
|
||||
if targetType.Kind() == reflect.Struct {
|
||||
structVal := reflect.New(targetType)
|
||||
if err := unmarshal(val.ComplexValue, structVal, targetType); err != nil {
|
||||
return reflect.Value{}, err
|
||||
} else {
|
||||
return structVal.Elem(), nil
|
||||
}
|
||||
} else if targetType.Kind() == reflect.Pointer && targetType.Elem().Kind() == reflect.Struct {
|
||||
structVal := reflect.New(targetType.Elem())
|
||||
if err := unmarshal(val.ComplexValue, structVal, targetType.Elem()); err != nil {
|
||||
return reflect.Value{}, err
|
||||
} else {
|
||||
return structVal, nil
|
||||
}
|
||||
} else {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected struct, got %s", ErrUnmatchingType, val.Type)
|
||||
}
|
||||
case rpcv1.ModuleSpec_ValueTypeMap:
|
||||
if targetType.Kind() != reflect.Map {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected map, got %v", ErrUnmatchingType, targetType)
|
||||
}
|
||||
|
||||
mapVal := reflect.MakeMap(targetType)
|
||||
|
||||
for k, v := range val.ComplexValue {
|
||||
if mappedVal, err := mapSpecValueTo(v, targetType.Elem()); err != nil {
|
||||
return reflect.Value{}, err
|
||||
} else {
|
||||
mapVal.SetMapIndex(reflect.ValueOf(k), mappedVal)
|
||||
}
|
||||
}
|
||||
|
||||
return mapVal, nil
|
||||
|
||||
case rpcv1.ModuleSpec_ValueTypeSingle:
|
||||
switch sv := val.SingleValue.(type) {
|
||||
case *rpcv1.ModuleSpec_Value_BoolValue:
|
||||
if targetType.Kind() != reflect.Bool {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected bool, got %v", ErrUnmatchingType, targetType)
|
||||
}
|
||||
return reflect.ValueOf(sv.BoolValue), nil
|
||||
case *rpcv1.ModuleSpec_Value_StringValue:
|
||||
if targetType.Kind() != reflect.String {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected string, got %v", ErrUnmatchingType, targetType)
|
||||
}
|
||||
return reflect.ValueOf(sv.StringValue), nil
|
||||
case *rpcv1.ModuleSpec_Value_IntValue:
|
||||
if targetType.Kind() != reflect.Int {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected int, got %v", ErrUnmatchingType, targetType)
|
||||
}
|
||||
return reflect.ValueOf(int(sv.IntValue)), nil
|
||||
case *rpcv1.ModuleSpec_Value_DoubleValue:
|
||||
if targetType.Kind() != reflect.Float64 {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected float64, got %v", ErrUnmatchingType, targetType)
|
||||
}
|
||||
return reflect.ValueOf(sv.DoubleValue), nil
|
||||
}
|
||||
case rpcv1.ModuleSpec_ValueTypeBoolSlice:
|
||||
if targetType.Kind() != reflect.Slice {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected slice, got %v", ErrUnmatchingType, targetType)
|
||||
} else if targetType.Elem().Kind() != reflect.Bool {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected bool, got %v", ErrUnmatchingType, targetType.Elem())
|
||||
}
|
||||
return reflect.ValueOf(val.BoolValues), nil
|
||||
case rpcv1.ModuleSpec_ValueTypeStringSlice:
|
||||
if targetType.Kind() != reflect.Slice {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected slice, got %v", ErrUnmatchingType, targetType)
|
||||
} else if targetType.Elem().Kind() != reflect.String {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected string, got %v", ErrUnmatchingType, targetType.Elem())
|
||||
}
|
||||
return reflect.ValueOf(val.StringValues), nil
|
||||
case rpcv1.ModuleSpec_ValueTypeIntSlice:
|
||||
if targetType.Kind() != reflect.Slice {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected slice, got %v", ErrUnmatchingType, targetType)
|
||||
}
|
||||
switch targetType.Elem().Kind() {
|
||||
case reflect.Int:
|
||||
return reflect.ValueOf(convertNumericSlice[int64, int](val.IntValues)), nil
|
||||
case reflect.Int8:
|
||||
return reflect.ValueOf(convertNumericSlice[int64, int8](val.IntValues)), nil
|
||||
case reflect.Int16:
|
||||
return reflect.ValueOf(convertNumericSlice[int64, int16](val.IntValues)), nil
|
||||
case reflect.Int32:
|
||||
return reflect.ValueOf(convertNumericSlice[int64, int32](val.IntValues)), nil
|
||||
case reflect.Int64:
|
||||
return reflect.ValueOf(val.IntValues), nil
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected int, got %v", ErrUnmatchingType, targetType.Elem())
|
||||
}
|
||||
case rpcv1.ModuleSpec_ValueTypeDoubleSlice:
|
||||
if targetType.Kind() != reflect.Slice {
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected slice, got %v", ErrUnmatchingType, targetType)
|
||||
}
|
||||
switch targetType.Elem().Kind() {
|
||||
case reflect.Float32:
|
||||
return reflect.ValueOf(convertNumericSlice[float64, float32](val.DoubleValues)), nil
|
||||
case reflect.Float64:
|
||||
return reflect.ValueOf(val.DoubleValues), nil
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("%w: expected int, got %v", ErrUnmatchingType, targetType.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
return reflect.Value{}, nil
|
||||
}
|
||||
|
||||
type numeric interface {
|
||||
constraints.Integer | constraints.Float
|
||||
}
|
||||
|
||||
func convertNumericSlice[TIn numeric, TOut numeric](input []TIn) []TOut {
|
||||
output := make([]TOut, len(input))
|
||||
for i, v := range input {
|
||||
output[i] = TOut(v)
|
||||
}
|
||||
return output
|
||||
}
|
|
@ -1,515 +0,0 @@
|
|||
package protocol_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/protocol"
|
||||
)
|
||||
|
||||
func TestUnmarshal_Bool_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Delete bool
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"delete": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_BoolValue{
|
||||
BoolValue: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if !target.Delete {
|
||||
t.Errorf("Expected Delete to be true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Bool_Err(t *testing.T) {
|
||||
target := struct {
|
||||
Delete string
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"delete": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_BoolValue{
|
||||
BoolValue: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err == nil {
|
||||
t.Errorf("Expected error")
|
||||
} else {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Bool_Slice_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Delete []bool
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"delete": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeBoolSlice,
|
||||
BoolValues: []bool{true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if len(target.Delete) < 1 {
|
||||
t.Errorf("Expected Delete to have at least one element")
|
||||
} else if !target.Delete[0] {
|
||||
t.Errorf("Expected Delete[0] to be true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Bool_Slice_Err(t *testing.T) {
|
||||
target := struct {
|
||||
Delete []string
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"delete": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeBoolSlice,
|
||||
BoolValues: []bool{true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err == nil {
|
||||
t.Errorf("Expected error")
|
||||
} else {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_String_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Name string
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"name": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_StringValue{
|
||||
StringValue: "Ted",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if target.Name != "Ted" {
|
||||
t.Errorf("Expected Name to be 'Ted'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_String_Err(t *testing.T) {
|
||||
target := struct {
|
||||
Name int
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"name": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_StringValue{
|
||||
StringValue: "Ted",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err == nil {
|
||||
t.Errorf("Expected error")
|
||||
} else {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_String_Slice_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Names []string
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"names": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeStringSlice,
|
||||
StringValues: []string{"Ted"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if len(target.Names) < 1 {
|
||||
t.Errorf("Expected Names to have at least one element")
|
||||
} else if target.Names[0] != "Ted" {
|
||||
t.Errorf("Expected Names[0] to be 'Ted'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_String_Slice_Err(t *testing.T) {
|
||||
target := struct {
|
||||
Names []int
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"names": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeStringSlice,
|
||||
StringValues: []string{"Ted"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err == nil {
|
||||
t.Errorf("Expected error")
|
||||
} else {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Int_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Age int
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"age": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_IntValue{
|
||||
IntValue: 42,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if target.Age != 42 {
|
||||
t.Errorf("Expected Age to be 42")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Int_Err(t *testing.T) {
|
||||
target := struct {
|
||||
Age string
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"age": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_IntValue{
|
||||
IntValue: 42,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err == nil {
|
||||
t.Errorf("Expected error")
|
||||
} else {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Int_Slice_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Ages []int
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"ages": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeIntSlice,
|
||||
IntValues: []int64{42},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if len(target.Ages) < 1 {
|
||||
t.Errorf("Expected Ages to have at least one element")
|
||||
} else if target.Ages[0] != 42 {
|
||||
t.Errorf("Expected Ages[0] to be 42")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Int_Slice_Err(t *testing.T) {
|
||||
target := struct {
|
||||
Ages []string
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"ages": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeIntSlice,
|
||||
IntValues: []int64{42},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err == nil {
|
||||
t.Errorf("Expected error")
|
||||
} else {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Double_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Pi float64
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"Pi": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_DoubleValue{
|
||||
DoubleValue: 3.14,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if target.Pi-3.14 > 0.0000001 {
|
||||
t.Errorf("Expected Pi to be 3.14")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Double_Err(t *testing.T) {
|
||||
target := struct {
|
||||
Pi string
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"pi": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_DoubleValue{
|
||||
DoubleValue: 3.14,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err == nil {
|
||||
t.Errorf("Expected error")
|
||||
} else {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Double_Slice_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Pis []float64
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"pis": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeDoubleSlice,
|
||||
DoubleValues: []float64{3.14},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if len(target.Pis) < 1 {
|
||||
t.Errorf("Expected Pis to have at least one element")
|
||||
} else if target.Pis[0]-3.14 > 0.0000001 {
|
||||
t.Errorf("Expected Pis[0] to be 3.14")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Double_Slice_Err(t *testing.T) {
|
||||
target := struct {
|
||||
Pis []string
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"pis": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeDoubleSlice,
|
||||
DoubleValues: []float64{3.14},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err == nil {
|
||||
t.Errorf("Expected error")
|
||||
} else {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_NestedStruct_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Address struct {
|
||||
City string
|
||||
}
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"address": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeObject,
|
||||
ComplexValue: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"city": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_StringValue{
|
||||
StringValue: "New York",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if target.Address.City != "New York" {
|
||||
t.Errorf("Expected City to be 'New York'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_NestedStructPointer_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Address *struct {
|
||||
City string
|
||||
}
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"address": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeObject,
|
||||
ComplexValue: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"city": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_StringValue{
|
||||
StringValue: "New York",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if target.Address.City != "New York" {
|
||||
t.Errorf("Expected City to be 'New York'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_Map_Success(t *testing.T) {
|
||||
target := struct {
|
||||
Values map[string]string
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"values": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeMap,
|
||||
ComplexValue: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"City": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_StringValue{
|
||||
StringValue: "New York",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if target.Values["City"] != "New York" {
|
||||
t.Errorf("Expected City to be 'New York'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_NestedMap_Success(t *testing.T) {
|
||||
target := struct {
|
||||
City struct {
|
||||
Labels map[string]string
|
||||
}
|
||||
}{}
|
||||
|
||||
spec := &rpcv1.ModuleSpec{
|
||||
Values: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"city": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeObject,
|
||||
ComplexValue: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"labels": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeMap,
|
||||
ComplexValue: map[string]*rpcv1.ModuleSpec_Value{
|
||||
"Region": {
|
||||
Type: rpcv1.ModuleSpec_ValueTypeSingle,
|
||||
SingleValue: &rpcv1.ModuleSpec_Value_StringValue{
|
||||
StringValue: "west",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := protocol.Unmarshal(spec, &target); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if target.City.Labels["Region"] != "west" {
|
||||
t.Errorf("Expected 'Region' to be 'west'")
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -10,9 +11,9 @@ import (
|
|||
prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||
v1Health "google.golang.org/grpc/health/grpc_health_v1"
|
||||
"google.golang.org/grpc/reflection"
|
||||
"log/slog"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/rpc/middleware"
|
||||
v1 "code.icb4dc0.de/buildr/buildr/internal/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/services"
|
||||
|
|
|
@ -3,13 +3,13 @@ package v1
|
|||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
|
||||
"log/slog"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
|
|
|
@ -9,8 +9,9 @@ import (
|
|||
"time"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/common/protocol"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/archive"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/protocol"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
|
@ -83,7 +84,7 @@ func (e *RemoteTaskExecutor) Execute(
|
|||
result := new(rpcv1.TaskResult)
|
||||
|
||||
if err != nil {
|
||||
result.Error = fmt.Sprintf("failed to execute module %s/%s: %s", mod.Category().String(), mod.Name(), err.Error())
|
||||
result.Error = fmt.Sprintf("failed to execute module %s/%s: %s", CategoryName(mod.Category()), mod.Name(), err.Error())
|
||||
}
|
||||
|
||||
e.logger.Debug("Waiting for file change events to propagate before canceling watcher")
|
||||
|
|
|
@ -5,14 +5,15 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/errs"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -5,11 +5,11 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"log/slog"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/archive"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/ignore"
|
||||
|
|
|
@ -2,10 +2,10 @@ package v1
|
|||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
v1 "google.golang.org/grpc/health/grpc_health_v1"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
const healthCheckInterval = 100 * time.Millisecond
|
||||
|
|
|
@ -5,12 +5,12 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"sync"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -3,13 +3,13 @@ package v1
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/errs"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
func newRemoteStateClient(
|
||||
|
@ -29,8 +29,8 @@ func newRemoteStateClient(
|
|||
type RemoteStateClient struct {
|
||||
logger *slog.Logger
|
||||
requestClient *RequestResponseClient
|
||||
cat modules.Category
|
||||
name string
|
||||
cat modules.Category
|
||||
}
|
||||
|
||||
func (c *RemoteStateClient) GetState(ctx context.Context, key string) ([]byte, state.Metadata, error) {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
"github.com/docker/docker/client"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/ignore"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/vault"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
|
|
|
@ -48,7 +48,7 @@ func WithIgnorer(ignorer *ignore.Ignorer) CollectionOption {
|
|||
|
||||
func WithDB(db *state.DB) CollectionOption {
|
||||
return collectionOptionFunc(func(svc *Collection) error {
|
||||
svc.stateDb = db
|
||||
svc.stateDB = db
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ type Collection struct {
|
|||
dockerClient *client.Client
|
||||
ignorer *ignore.Ignorer
|
||||
stateStore state.Store
|
||||
stateDb *state.DB
|
||||
stateDB *state.DB
|
||||
cache state.Cache
|
||||
diagsWriter hcl.DiagnosticWriter
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ func (c *Collection) DiagsWriter() hcl.DiagnosticWriter {
|
|||
}
|
||||
|
||||
func (c *Collection) PluginsRepo() state.Plugins {
|
||||
return c.stateDb.Plugins
|
||||
return c.stateDB.Plugins
|
||||
}
|
||||
|
||||
func (c *Collection) Close() error {
|
||||
|
@ -162,8 +162,8 @@ func (c *Collection) Close() error {
|
|||
err = c.dockerClient.Close()
|
||||
}
|
||||
|
||||
if c.stateDb != nil {
|
||||
err = errors.Join(c.stateDb.Close())
|
||||
if c.stateDB != nil {
|
||||
err = errors.Join(c.stateDB.Close())
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
3
main.go
3
main.go
|
@ -3,11 +3,10 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"log/slog"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/cmd"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/errs"
|
||||
)
|
||||
|
|
|
@ -3,11 +3,11 @@ package modules
|
|||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
type ExecutionContext interface {
|
||||
|
@ -48,7 +48,7 @@ type Initializer interface {
|
|||
}
|
||||
|
||||
type Helper interface {
|
||||
Help() (help Help, okay bool)
|
||||
Help(ctx context.Context) (help Help, err error)
|
||||
}
|
||||
|
||||
type Module interface {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/hashicorp/hcl/v2/gohcl"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
"code.icb4dc0.de/buildr/buildr/internal/protocol"
|
||||
"code.icb4dc0.de/buildr/common/protocol"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
@ -12,7 +13,6 @@ import (
|
|||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
|
||||
"github.com/klauspost/compress/zip"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
var _ modules.Module = (*ZipArchive)(nil)
|
||||
|
|
|
@ -4,11 +4,11 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/daemon"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
func newContainerDaemon(imageName string, logger *slog.Logger, tags []string, cli daemon.Client) containerDaemon {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -18,7 +19,6 @@ import (
|
|||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
specsv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"log/slog"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
|
|
@ -11,7 +11,8 @@ import (
|
|||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/maps"
|
||||
)
|
||||
|
||||
type registryPublisherOption func(p *registryPublisher)
|
||||
|
|
187
modules/plugin/exec_context.go
Normal file
187
modules/plugin/exec_context.go
Normal file
|
@ -0,0 +1,187 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/sh"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
type wasiPluginExecContext struct {
|
||||
ctx modules.ExecutionContext
|
||||
memMgr *memoryManager
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) lookPath(ctx context.Context, m api.Module, offset, byteCount uint32) uint64 {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
lookupPathReq := new(rpcv1.LookupPathRequest)
|
||||
if err := proto.Unmarshal(buf, lookupPathReq); err != nil {
|
||||
c.ctx.Logger().Error("failed to unmarshal LookupPathRequest", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
if lookupPathReq.Command == "" {
|
||||
c.ctx.Logger().Error("cannot lookup empty command")
|
||||
return 0
|
||||
}
|
||||
|
||||
foundPath, err := exec.LookPath(lookupPathReq.Command)
|
||||
|
||||
lookupPathResp := &rpcv1.LookupPathResponse{
|
||||
Path: foundPath,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
lookupPathResp.Error = err.Error()
|
||||
}
|
||||
|
||||
if ptrSize, err := c.memMgr.WriteMessage(ctx, m, lookupPathResp); err != nil {
|
||||
c.ctx.Logger().Error("Failed to write message", slog.String("err", err.Error()))
|
||||
return 0
|
||||
} else {
|
||||
return ptrSize
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) exec(ctx context.Context, m api.Module, offset, byteCount uint32) uint64 {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
execReq := new(rpcv1.ProcessStartRequest)
|
||||
if err := proto.Unmarshal(buf, execReq); err != nil {
|
||||
c.ctx.Logger().Error("failed to unmarshal ProcessStartRequest", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
execResp := new(rpcv1.ProcessStartResponse)
|
||||
|
||||
//nolint:contextcheck // that ain't a context.Context
|
||||
cmd, err := sh.PrepareCommand(c.ctx, execReq.Command, execReq.Args...)
|
||||
if err != nil {
|
||||
c.ctx.Logger().Error("failed to prepare command", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
cmd.AddEnv(execReq.Environment)
|
||||
if len(execReq.Stdin) > 0 {
|
||||
cmd.SetStdIn(bytes.NewReader(execReq.Stdin))
|
||||
}
|
||||
|
||||
if len(execReq.WorkingDirectory) > 0 {
|
||||
cmd.SetWorkingDir(execReq.WorkingDirectory)
|
||||
}
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
execResp.ExitCode = int32(exitErr.ExitCode())
|
||||
execResp.Stderr = exitErr.Stderr
|
||||
} else {
|
||||
execResp.ExitCode = 1
|
||||
}
|
||||
execResp.Error = err.Error()
|
||||
}
|
||||
|
||||
if ptrSize, err := c.memMgr.WriteMessage(ctx, m, execResp); err != nil {
|
||||
c.ctx.Logger().Error("Failed to write message", slog.String("err", err.Error()))
|
||||
return 0
|
||||
} else {
|
||||
return ptrSize
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) log(ctx context.Context, m api.Module, offset, byteCount uint32) {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
logger := c.ctx.Logger()
|
||||
taskLog := new(rpcv1.TaskLog)
|
||||
if err := proto.Unmarshal(buf, taskLog); err != nil {
|
||||
logger.Warn("failed to unmarshal task log", slog.String("err", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
rec := slog.NewRecord(time.UnixMicro(taskLog.Time), slog.Level(taskLog.Level), taskLog.Message, 0)
|
||||
|
||||
for i := range taskLog.Attributes {
|
||||
attr := taskLog.Attributes[i]
|
||||
rec.AddAttrs(slog.String(attr.Key, attr.Value))
|
||||
}
|
||||
|
||||
_ = logger.Handler().Handle(ctx, rec)
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) getState(ctx context.Context, m api.Module, offset, byteCount uint32) uint64 {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
getStateReq := new(rpcv1.GetStateRequest)
|
||||
if err := proto.Unmarshal(buf, getStateReq); err != nil {
|
||||
c.ctx.Logger().Error("failed to unmarshal getStateRequest", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
resp := new(rpcv1.GetStateResponse)
|
||||
val, _, err := c.ctx.GetState(ctx, string(getStateReq.Key))
|
||||
if err != nil {
|
||||
c.ctx.Logger().Error("failed to get state", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
resp.Data = val
|
||||
|
||||
if ptrSize, err := c.memMgr.WriteMessage(ctx, m, resp); err != nil {
|
||||
c.ctx.Logger().Error("Failed to write message", slog.String("err", err.Error()))
|
||||
return 0
|
||||
} else {
|
||||
return ptrSize
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) setState(ctx context.Context, m api.Module, offset, byteCount uint32) (result uint64) {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
setState := new(rpcv1.SetState)
|
||||
if err := proto.Unmarshal(buf, setState); err != nil {
|
||||
c.ctx.Logger().Error("failed to unmarshal SetState", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
var resp rpcv1.Result
|
||||
if err := c.ctx.SetState(ctx, string(setState.Key), setState.Data); err != nil {
|
||||
c.ctx.Logger().Error("failed to set state", slog.String("err", err.Error()))
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Success = true
|
||||
}
|
||||
|
||||
if ptrSize, err := c.memMgr.WriteMessage(ctx, m, &resp); err != nil {
|
||||
c.ctx.Logger().Error("Failed to write message", slog.String("err", err.Error()))
|
||||
return 0
|
||||
} else {
|
||||
return ptrSize
|
||||
}
|
||||
}
|
202
modules/plugin/help.go
Normal file
202
modules/plugin/help.go
Normal file
|
@ -0,0 +1,202 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
//nolint:funlen // not much value in splitting hereG22
|
||||
func (m Module) Help(ctx context.Context) (help modules.Help, err error) {
|
||||
runtime := m.prepareWASIRuntime(ctx)
|
||||
|
||||
defer func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
_ = runtime.Close(ctx)
|
||||
}()
|
||||
|
||||
_, err = runtime.NewHostModuleBuilder("buildr").
|
||||
NewFunctionBuilder().WithFunc(dummyWithoutResult).Export("log_msg").
|
||||
NewFunctionBuilder().WithFunc(dummyWithResult).Export("get_state").
|
||||
NewFunctionBuilder().WithFunc(dummyWithResult).Export("set_state").
|
||||
NewFunctionBuilder().WithFunc(dummyWithResult).Export("exec").
|
||||
NewFunctionBuilder().WithFunc(dummyWithResult).Export("lookPath").
|
||||
Instantiate(ctx)
|
||||
|
||||
if err != nil {
|
||||
return modules.Help{}, err
|
||||
}
|
||||
|
||||
closer, err := wasi_snapshot_preview1.Instantiate(ctx, runtime)
|
||||
if err != nil {
|
||||
return modules.Help{}, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if closeErr := closer.Close(context.Background()); closeErr != nil {
|
||||
err = errors.Join(err, fmt.Errorf("failed to close WASI runtime: %w", closeErr))
|
||||
}
|
||||
}()
|
||||
|
||||
moduleConfig := wazero.NewModuleConfig().
|
||||
WithStdout(io.Discard).
|
||||
WithStderr(io.Discard)
|
||||
|
||||
pluginPayload, err := m.PluginPayload.Bytes()
|
||||
if err != nil {
|
||||
return modules.Help{}, err
|
||||
}
|
||||
|
||||
mod, err := runtime.InstantiateWithConfig(ctx, pluginPayload, moduleConfig)
|
||||
if err != nil {
|
||||
return modules.Help{}, err
|
||||
}
|
||||
|
||||
memMgr := newMemoryManager(mod)
|
||||
|
||||
helpRequest := &rpcv1.HelpRequest{
|
||||
ModuleReference: &rpcv1.ModuleReference{
|
||||
ModuleCategory: m.PluginCategory,
|
||||
ModuleType: m.PluginType,
|
||||
},
|
||||
}
|
||||
|
||||
data, err := proto.Marshal(helpRequest)
|
||||
if err != nil {
|
||||
return modules.Help{}, err
|
||||
}
|
||||
|
||||
helpFunc := mod.ExportedFunction("help")
|
||||
|
||||
var helpResult rpcv1.HelpResponse
|
||||
err = memMgr.WithMem(ctx, uint64(len(data)), func(ptr uint64) error {
|
||||
if !mod.Memory().Write(uint32(ptr), data) {
|
||||
return errors.New("failed to write to memory")
|
||||
}
|
||||
|
||||
result, err := helpFunc.Call(ctx, ptr, uint64(len(data)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run WASI module: %w", err)
|
||||
}
|
||||
|
||||
resultPtr, resultSize := uint32(result[0]>>defaultIntegerSize), uint32(result[0])
|
||||
if ptr == 0 {
|
||||
return errors.New("failed to get inventory - 0 pointer")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err = errors.Join(err, memMgr.Deallocate(ctx, ptr))
|
||||
}()
|
||||
|
||||
data, ok := mod.Memory().Read(resultPtr, resultSize)
|
||||
if !ok {
|
||||
return errors.New("failed to get inventory")
|
||||
}
|
||||
|
||||
if err = proto.Unmarshal(data, &helpResult); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal inventory: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return modules.Help{}, err
|
||||
}
|
||||
|
||||
moduleHelp := modules.Help{
|
||||
Name: helpResult.Name,
|
||||
Description: helpResult.Description,
|
||||
Examples: m.mapToExamples(helpResult.Examples),
|
||||
}
|
||||
|
||||
return moduleHelp, nil
|
||||
}
|
||||
|
||||
func (m Module) mapToExamples(raw []*rpcv1.TaskExample) []modules.Example {
|
||||
examples := make([]modules.Example, 0, len(raw))
|
||||
|
||||
for _, example := range raw {
|
||||
spec := &modules.Metadata[Module]{
|
||||
Module: Module{
|
||||
PluginCategory: m.Category(),
|
||||
PluginType: m.Type(),
|
||||
PluginPayload: m.PluginPayload,
|
||||
modSpec: example.TaskSpec.ModuleSpec,
|
||||
},
|
||||
ModuleName: example.TaskSpec.ModuleName,
|
||||
OutputDir: example.TaskSpec.OutputDir,
|
||||
}
|
||||
|
||||
if example.TaskSpec.Container != nil {
|
||||
spec.Container = &modules.ContainerSpec{
|
||||
Image: example.TaskSpec.Container.Image,
|
||||
User: example.TaskSpec.Container.User,
|
||||
BindMounts: nil,
|
||||
Privileged: example.TaskSpec.Container.Privileged,
|
||||
}
|
||||
|
||||
if example.TaskSpec.Container.Capabilities != nil {
|
||||
spec.Container.Capabilities = &modules.ContainerCapabilities{
|
||||
Add: example.TaskSpec.Container.Capabilities.Add,
|
||||
Drop: example.TaskSpec.Container.Capabilities.Drop,
|
||||
}
|
||||
}
|
||||
|
||||
if example.TaskSpec.Container.VolumeMounts != nil {
|
||||
spec.Container.VolumeMounts = make([]modules.ContainerVolumeMount, 0, len(example.TaskSpec.Container.VolumeMounts))
|
||||
|
||||
for _, v := range example.TaskSpec.Container.VolumeMounts {
|
||||
spec.Container.VolumeMounts = append(spec.Container.VolumeMounts, modules.ContainerVolumeMount{
|
||||
Target: v.Target,
|
||||
Name: v.Name,
|
||||
ReadOnly: v.ReadOnly,
|
||||
NoCopy: v.NoCopy,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if example.TaskSpec.Container.TmpfsMounts != nil {
|
||||
spec.Container.TmpfsMounts = make([]modules.ContainerTmpfsMount, 0, len(example.TaskSpec.Container.TmpfsMounts))
|
||||
|
||||
for _, v := range example.TaskSpec.Container.TmpfsMounts {
|
||||
spec.Container.TmpfsMounts = append(spec.Container.TmpfsMounts, modules.ContainerTmpfsMount{
|
||||
Target: v.Target,
|
||||
ReadOnly: v.ReadOnly,
|
||||
Size: v.Size,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if example.TaskSpec.Container.BindMounts != nil {
|
||||
spec.Container.BindMounts = make([]modules.ContainerBindMount, 0, len(example.TaskSpec.Container.BindMounts))
|
||||
|
||||
for _, v := range example.TaskSpec.Container.BindMounts {
|
||||
spec.Container.BindMounts = append(spec.Container.BindMounts, modules.ContainerBindMount{
|
||||
Source: v.Source,
|
||||
Target: v.Target,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
examples = append(examples, modules.Example{
|
||||
Name: example.Name,
|
||||
Description: example.Description,
|
||||
Spec: spec,
|
||||
})
|
||||
}
|
||||
|
||||
return examples
|
||||
}
|
90
modules/plugin/marshal.go
Normal file
90
modules/plugin/marshal.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/hcl/v2/hclwrite"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/hcl"
|
||||
)
|
||||
|
||||
func (m Module) MarshalHCL(block *hclwrite.Block) error {
|
||||
for s, value := range m.modSpec.Values {
|
||||
switch value.Kind {
|
||||
case rpcv1.ModuleSpec_ValueKindUnknown, rpcv1.ModuleSpec_ValueKindAttribute:
|
||||
if mapped, err := mapSpecValueToCty(value); err != nil {
|
||||
return err
|
||||
} else {
|
||||
block.Body().SetAttributeValue(s, mapped)
|
||||
}
|
||||
case rpcv1.ModuleSpec_ValueKindBlock:
|
||||
case rpcv1.ModuleSpec_ValueKindLabel:
|
||||
if value.Type != rpcv1.ModuleSpec_ValueTypeSingle {
|
||||
return errors.New("only single values are supported as labels")
|
||||
}
|
||||
|
||||
if value.SingleValue == nil {
|
||||
return errors.New("single value is nil")
|
||||
}
|
||||
|
||||
if s, ok := value.SingleValue.(*rpcv1.ModuleSpec_Value_StringValue); !ok {
|
||||
return errors.New("single value is not a string - only strings are supported as labels")
|
||||
} else {
|
||||
block.SetLabels(append(block.Labels(), s.StringValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:gocyclo // cannot be less complex
|
||||
func mapSpecValueToCty(value *rpcv1.ModuleSpec_Value) (cty.Value, error) {
|
||||
switch value.Type {
|
||||
case rpcv1.ModuleSpec_ValueTypeUnknown:
|
||||
return cty.Value{}, errors.New("cannot map unknown value type")
|
||||
case rpcv1.ModuleSpec_ValueTypeSingle:
|
||||
switch v := value.SingleValue.(type) {
|
||||
case *rpcv1.ModuleSpec_Value_BoolValue:
|
||||
return cty.BoolVal(v.BoolValue), nil
|
||||
case *rpcv1.ModuleSpec_Value_StringValue:
|
||||
return cty.StringVal(v.StringValue), nil
|
||||
case *rpcv1.ModuleSpec_Value_IntValue:
|
||||
return cty.NumberIntVal(v.IntValue), nil
|
||||
case *rpcv1.ModuleSpec_Value_DoubleValue:
|
||||
return cty.NumberFloatVal(v.DoubleValue), nil
|
||||
default:
|
||||
return cty.NilVal, fmt.Errorf("unsupported value type %q", value.Type)
|
||||
}
|
||||
case rpcv1.ModuleSpec_ValueTypeStringSlice:
|
||||
return hcl.MapToCtyVal(value.StringValues, hcl.MappingCfg{})
|
||||
case rpcv1.ModuleSpec_ValueTypeIntSlice:
|
||||
return hcl.MapToCtyVal(value.IntValues, hcl.MappingCfg{})
|
||||
case rpcv1.ModuleSpec_ValueTypeDoubleSlice:
|
||||
return hcl.MapToCtyVal(value.DoubleValues, hcl.MappingCfg{})
|
||||
case rpcv1.ModuleSpec_ValueTypeBoolSlice:
|
||||
return hcl.MapToCtyVal(value.BoolValues, hcl.MappingCfg{})
|
||||
case rpcv1.ModuleSpec_ValueTypeObject:
|
||||
return cty.Value{}, errors.New("object type are right now not supported (yet)")
|
||||
case rpcv1.ModuleSpec_ValueTypeMap:
|
||||
if len(value.ComplexValue) == 0 {
|
||||
return cty.MapValEmpty(cty.String), nil
|
||||
}
|
||||
mappedVal := make(map[string]cty.Value, len(value.ComplexValue))
|
||||
|
||||
for k, v := range value.ComplexValue {
|
||||
if mapped, err := mapSpecValueToCty(v); err != nil {
|
||||
return cty.Value{}, err
|
||||
} else {
|
||||
mappedVal[k] = mapped
|
||||
}
|
||||
}
|
||||
|
||||
return cty.MapVal(mappedVal), nil
|
||||
default:
|
||||
return cty.NilVal, fmt.Errorf("unsupported value type %q", value.Type)
|
||||
}
|
||||
}
|
|
@ -1,30 +1,17 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/sh"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/ioutils"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/hcl"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
|
||||
"github.com/hashicorp/hcl/v2/hclwrite"
|
||||
|
||||
"github.com/google/uuid"
|
||||
hcl2 "github.com/hashicorp/hcl/v2"
|
||||
"github.com/klauspost/compress/s2"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
|
@ -32,45 +19,27 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
_ modules.Module = (*Module)(nil)
|
||||
_ hcl.Marshaler = (*Module)(nil)
|
||||
_ json.Marshaler = (*Module)(nil)
|
||||
_ json.Unmarshaler = (*Module)(nil)
|
||||
_ modules.Module = (*Module)(nil)
|
||||
_ hcl.Marshaler = (*Module)(nil)
|
||||
_ modules.Helper = (*Module)(nil)
|
||||
_ modules.Initializer = (*Module)(nil)
|
||||
)
|
||||
|
||||
type jsonPluginModule struct {
|
||||
ModuleSpec *rpcv1.ModuleSpec `json:"module_spec"`
|
||||
PluginCategory modules.Category `json:"plugin_category"`
|
||||
PluginType string `json:"plugin_type"`
|
||||
PluginPayload []byte `json:"plugin_payload"`
|
||||
}
|
||||
|
||||
type Module struct {
|
||||
ModuleSpec map[string]any `hcl:",remain"`
|
||||
PluginCategory modules.Category
|
||||
PluginType string
|
||||
PluginPayload PayloadReader
|
||||
ModuleSpec map[string]any `hcl:",remain"`
|
||||
modSpec *rpcv1.ModuleSpec
|
||||
}
|
||||
|
||||
func (m Module) MarshalHCL(*hclwrite.Block) error {
|
||||
return errors.New("plugin modules cannot be marshaled to HCL right now")
|
||||
PluginType string
|
||||
PluginCategory modules.Category
|
||||
}
|
||||
|
||||
func (m Module) Execute(ctx modules.ExecutionContext) (err error) {
|
||||
runtimeConfig := wazero.NewRuntimeConfig().
|
||||
WithCloseOnContextDone(true)
|
||||
runtime := m.prepareWASIRuntime(ctx)
|
||||
|
||||
pluginpayload, err := m.PluginPayload.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := wazero.NewRuntimeWithConfig(ctx, runtimeConfig)
|
||||
defer func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
if closeErr := r.Close(ctx); closeErr != nil {
|
||||
if closeErr := runtime.Close(ctx); closeErr != nil {
|
||||
err = errors.Join(err, fmt.Errorf("failed to close runtime: %w", closeErr))
|
||||
}
|
||||
}()
|
||||
|
@ -79,7 +48,7 @@ func (m Module) Execute(ctx modules.ExecutionContext) (err error) {
|
|||
ctx: ctx,
|
||||
}
|
||||
|
||||
_, err = r.NewHostModuleBuilder("buildr").
|
||||
_, err = runtime.NewHostModuleBuilder("buildr").
|
||||
NewFunctionBuilder().WithFunc(wasiCtx.log).Export("log_msg").
|
||||
NewFunctionBuilder().WithFunc(wasiCtx.getState).Export("get_state").
|
||||
NewFunctionBuilder().WithFunc(wasiCtx.setState).Export("set_state").
|
||||
|
@ -91,7 +60,7 @@ func (m Module) Execute(ctx modules.ExecutionContext) (err error) {
|
|||
return fmt.Errorf("failed to instantiate host module: %w", err)
|
||||
}
|
||||
|
||||
closer, err := wasi_snapshot_preview1.Instantiate(ctx, r)
|
||||
closer, err := wasi_snapshot_preview1.Instantiate(ctx, runtime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to instantiate WASI infrastructure: %w", err)
|
||||
}
|
||||
|
@ -107,7 +76,12 @@ func (m Module) Execute(ctx modules.ExecutionContext) (err error) {
|
|||
WithStderr(ctx.StdErr()).
|
||||
WithFS(newMultiDirFS(ctx.WorkingDir(), ctx.OutDir()))
|
||||
|
||||
mod, err := r.InstantiateWithConfig(ctx, pluginpayload, moduleConfig)
|
||||
pluginPayload, err := m.PluginPayload.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mod, err := runtime.InstantiateWithConfig(ctx, pluginPayload, moduleConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to instantiate WASI module: %w", err)
|
||||
}
|
||||
|
@ -129,6 +103,7 @@ func (m Module) Execute(ctx modules.ExecutionContext) (err error) {
|
|||
Root: ctx.WorkingDir(),
|
||||
},
|
||||
OutDir: ctx.OutDir(),
|
||||
BinDir: ctx.BinariesDir(),
|
||||
},
|
||||
Spec: m.modSpec,
|
||||
}
|
||||
|
@ -165,6 +140,10 @@ func (m Module) Type() string {
|
|||
return m.PluginType
|
||||
}
|
||||
|
||||
func (m *Module) SetModuleSpec(spec *rpcv1.ModuleSpec) {
|
||||
m.modSpec = spec
|
||||
}
|
||||
|
||||
func (m Module) Init(hclCtx *hcl2.EvalContext) (modules.Module, error) {
|
||||
m.modSpec = &rpcv1.ModuleSpec{
|
||||
Category: m.PluginCategory,
|
||||
|
@ -173,8 +152,7 @@ func (m Module) Init(hclCtx *hcl2.EvalContext) (modules.Module, error) {
|
|||
}
|
||||
|
||||
for k, v := range m.ModuleSpec {
|
||||
switch a := v.(type) {
|
||||
case *hcl2.Attribute:
|
||||
if a, ok := v.(*hcl2.Attribute); ok {
|
||||
val, err := a.Expr.Value(hclCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -186,214 +164,12 @@ func (m Module) Init(hclCtx *hcl2.EvalContext) (modules.Module, error) {
|
|||
return m, nil
|
||||
}
|
||||
|
||||
func (m *Module) UnmarshalJSON(data []byte) (err error) {
|
||||
var jpm jsonPluginModule
|
||||
func (Module) prepareWASIRuntime(ctx context.Context) wazero.Runtime {
|
||||
runtimeConfig := wazero.
|
||||
NewRuntimeConfig().
|
||||
WithCloseOnContextDone(true)
|
||||
|
||||
if err := json.Unmarshal(data, &jpm); err != nil {
|
||||
return err
|
||||
}
|
||||
r := wazero.NewRuntimeWithConfig(ctx, runtimeConfig)
|
||||
|
||||
reader := s2.NewReader(bytes.NewReader(jpm.PluginPayload))
|
||||
|
||||
if plainData, err := io.ReadAll(reader); err != nil {
|
||||
return err
|
||||
} else {
|
||||
m.PluginPayload = MemoryPayload(plainData)
|
||||
}
|
||||
|
||||
m.PluginCategory = jpm.PluginCategory
|
||||
m.PluginType = jpm.PluginType
|
||||
m.modSpec = jpm.ModuleSpec
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Module) MarshalJSON() ([]byte, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
writer := s2.NewWriter(buf)
|
||||
|
||||
if _, err := ioutils.CopyWithPooledBuffer(writer, m.PluginPayload.Reader()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
jpm := jsonPluginModule{
|
||||
PluginCategory: m.PluginCategory,
|
||||
PluginType: m.PluginType,
|
||||
PluginPayload: buf.Bytes(),
|
||||
ModuleSpec: m.modSpec,
|
||||
}
|
||||
|
||||
return json.Marshal(jpm)
|
||||
}
|
||||
|
||||
type wasiPluginExecContext struct {
|
||||
ctx modules.ExecutionContext
|
||||
memMgr *memoryManager
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) lookPath(ctx context.Context, m api.Module, offset, byteCount uint32) uint64 {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
lookupPathReq := new(rpcv1.LookupPathRequest)
|
||||
if err := proto.Unmarshal(buf, lookupPathReq); err != nil {
|
||||
c.ctx.Logger().Error("failed to unmarshal LookupPathRequest", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
if lookupPathReq.Command == "" {
|
||||
c.ctx.Logger().Error("cannot lookup empty command")
|
||||
return 0
|
||||
}
|
||||
|
||||
foundPath, err := exec.LookPath(lookupPathReq.Command)
|
||||
|
||||
lookupPathResp := &rpcv1.LookupPathResponse{
|
||||
Path: foundPath,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
lookupPathResp.Error = err.Error()
|
||||
}
|
||||
|
||||
if ptrSize, err := c.memMgr.WriteMessage(ctx, m, lookupPathResp); err != nil {
|
||||
c.ctx.Logger().Error("Failed to write message", slog.String("err", err.Error()))
|
||||
return 0
|
||||
} else {
|
||||
return ptrSize
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) exec(ctx context.Context, m api.Module, offset, byteCount uint32) uint64 {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
execReq := new(rpcv1.ProcessStartRequest)
|
||||
if err := proto.Unmarshal(buf, execReq); err != nil {
|
||||
c.ctx.Logger().Error("failed to unmarshal ProcessStartRequest", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
execResp := new(rpcv1.ProcessStartResponse)
|
||||
|
||||
cmd, err := sh.PrepareCommand(c.ctx, execReq.Command, execReq.Args...)
|
||||
if err != nil {
|
||||
c.ctx.Logger().Error("failed to prepare command", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
cmd.AddEnv(execReq.Environment)
|
||||
if len(execReq.Stdin) > 0 {
|
||||
cmd.SetStdIn(bytes.NewReader(execReq.Stdin))
|
||||
}
|
||||
|
||||
if len(execReq.WorkingDirectory) > 0 {
|
||||
cmd.SetWorkingDir(execReq.WorkingDirectory)
|
||||
}
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
execResp.ExitCode = int32(exitErr.ExitCode())
|
||||
execResp.Stderr = exitErr.Stderr
|
||||
} else {
|
||||
execResp.ExitCode = 1
|
||||
}
|
||||
execResp.Error = err.Error()
|
||||
}
|
||||
|
||||
if ptrSize, err := c.memMgr.WriteMessage(ctx, m, execResp); err != nil {
|
||||
c.ctx.Logger().Error("Failed to write message", slog.String("err", err.Error()))
|
||||
return 0
|
||||
} else {
|
||||
return ptrSize
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) log(ctx context.Context, m api.Module, offset, byteCount uint32) {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
logger := c.ctx.Logger()
|
||||
taskLog := new(rpcv1.TaskLog)
|
||||
if err := proto.Unmarshal(buf, taskLog); err != nil {
|
||||
logger.Warn("failed to unmarshal task log", slog.String("err", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
rec := slog.NewRecord(time.UnixMicro(taskLog.Time), slog.Level(taskLog.Level), taskLog.Message, 0)
|
||||
|
||||
for i := range taskLog.Attributes {
|
||||
attr := taskLog.Attributes[i]
|
||||
rec.AddAttrs(slog.String(attr.Key, attr.Value))
|
||||
}
|
||||
|
||||
_ = logger.Handler().Handle(ctx, rec)
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) getState(ctx context.Context, m api.Module, offset, byteCount uint32) uint64 {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
getStateReq := new(rpcv1.GetStateRequest)
|
||||
if err := proto.Unmarshal(buf, getStateReq); err != nil {
|
||||
c.ctx.Logger().Error("failed to unmarshal getStateRequest", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
resp := new(rpcv1.GetStateResponse)
|
||||
val, _, err := c.ctx.GetState(ctx, string(getStateReq.Key))
|
||||
if err != nil {
|
||||
c.ctx.Logger().Error("failed to get state", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
resp.Data = val
|
||||
|
||||
if ptrSize, err := c.memMgr.WriteMessage(ctx, m, resp); err != nil {
|
||||
c.ctx.Logger().Error("Failed to write message", slog.String("err", err.Error()))
|
||||
return 0
|
||||
} else {
|
||||
return ptrSize
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wasiPluginExecContext) setState(ctx context.Context, m api.Module, offset, byteCount uint32) (result uint64) {
|
||||
buf, ok := m.Memory().Read(offset, byteCount)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
setState := new(rpcv1.SetState)
|
||||
if err := proto.Unmarshal(buf, setState); err != nil {
|
||||
c.ctx.Logger().Error("failed to unmarshal SetState", slog.String("err", err.Error()))
|
||||
return 0
|
||||
}
|
||||
|
||||
var resp rpcv1.Result
|
||||
if err := c.ctx.SetState(ctx, string(setState.Key), setState.Data); err != nil {
|
||||
c.ctx.Logger().Error("failed to set state", slog.String("err", err.Error()))
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Success = true
|
||||
}
|
||||
|
||||
if ptrSize, err := c.memMgr.WriteMessage(ctx, m, &resp); err != nil {
|
||||
c.ctx.Logger().Error("Failed to write message", slog.String("err", err.Error()))
|
||||
return 0
|
||||
} else {
|
||||
return ptrSize
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package plugin
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
@ -28,9 +30,10 @@ func (m MemoryPayload) Bytes() ([]byte, error) {
|
|||
}
|
||||
|
||||
type PayloadFile struct {
|
||||
readOnce sync.Once
|
||||
payload []byte
|
||||
Path string
|
||||
payload []byte
|
||||
Checksum []byte
|
||||
readOnce sync.Once
|
||||
}
|
||||
|
||||
func (f *PayloadFile) Reader() io.Reader {
|
||||
|
@ -48,6 +51,16 @@ func (f *PayloadFile) Bytes() ([]byte, error) {
|
|||
func (f *PayloadFile) readPayloadFile() (err error) {
|
||||
f.readOnce.Do(func() {
|
||||
f.payload, err = os.ReadFile(f.Path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hash := sha256.New()
|
||||
_, _ = hash.Write(f.payload)
|
||||
actualHash := hash.Sum(nil)
|
||||
if !bytes.Equal(f.Checksum, actualHash) {
|
||||
err = fmt.Errorf("plugin checksum mismatch: expected %x, got %x", f.Checksum, actualHash)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ func unwrap(val cty.Value) *rpcv1.ModuleSpec_Value {
|
|||
},
|
||||
}
|
||||
case val.Type().IsTupleType():
|
||||
//nolint:gocritic // eventually, there will be more cases
|
||||
switch {
|
||||
case val.Type().TupleElementTypes()[0].Equals(cty.String):
|
||||
specVal := &rpcv1.ModuleSpec_Value{
|
||||
|
@ -48,6 +49,7 @@ func unwrap(val cty.Value) *rpcv1.ModuleSpec_Value {
|
|||
Type: rpcv1.ModuleSpec_ValueTypeMap,
|
||||
ComplexValue: make(map[string]*rpcv1.ModuleSpec_Value, len(valueMap)),
|
||||
}
|
||||
//nolint:gocritic // eventually, there will be more cases
|
||||
switch {
|
||||
case val.Type().MapElementType().Equals(cty.String):
|
||||
for k, v := range valueMap {
|
||||
|
|
|
@ -82,10 +82,10 @@ func (r *TypeRegistry) CreateFromHCL(
|
|||
|
||||
unwrapped := mod.Unwrap()
|
||||
if initializer, ok := unwrapped.(Initializer); ok {
|
||||
if m, err := initializer.Init(hclCtx); err != nil {
|
||||
if initialized, err := initializer.Init(hclCtx); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
mod.SetModule(m)
|
||||
mod.SetModule(initialized)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,6 @@ func specOf(typeName Category, moduleName string) moduleSpec {
|
|||
}
|
||||
|
||||
type moduleSpec struct {
|
||||
TypeName Category
|
||||
ModuleName string
|
||||
TypeName Category
|
||||
}
|
||||
|
|
|
@ -48,6 +48,6 @@ type Plugins interface {
|
|||
List(ctx context.Context) ([]Plugin, error)
|
||||
Remove(ctx context.Context, id uuid.UUID) error
|
||||
ModulesForPlugin(ctx context.Context, id uuid.UUID) ([]PluginModule, error)
|
||||
UpsertPlugin(ctx context.Context, plugin Plugin) (pluginId uuid.UUID, err error)
|
||||
UpsertPlugin(ctx context.Context, plugin Plugin) (pluginID uuid.UUID, err error)
|
||||
UpsertModules(ctx context.Context, modules []PluginModule) error
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"net/url"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state/ent"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
@ -18,10 +19,11 @@ type Plugin struct {
|
|||
}
|
||||
|
||||
type PluginModule struct {
|
||||
ID *uuid.UUID
|
||||
PluginID uuid.UUID
|
||||
Type string
|
||||
Category rpcv1.Category
|
||||
ID *uuid.UUID
|
||||
Type string
|
||||
DefaultSpec []byte
|
||||
Category rpcv1.Category
|
||||
PluginID uuid.UUID
|
||||
}
|
||||
|
||||
func pluginFromEntity(p *ent.Plugin) (Plugin, error) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
|
||||
rpcv1 "code.icb4dc0.de/buildr/api/generated/rpc/v1"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state/ent"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state/ent/plugin"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state/ent/pluginmodule"
|
||||
|
@ -38,11 +39,13 @@ func (e EntPluginsRepo) ModulesForPlugin(ctx context.Context, id uuid.UUID) ([]P
|
|||
|
||||
result := make([]PluginModule, 0, len(modules))
|
||||
for _, module := range modules {
|
||||
module := module
|
||||
result = append(result, PluginModule{
|
||||
ID: &module.ID,
|
||||
PluginID: id,
|
||||
Type: module.Type,
|
||||
Category: rpcv1.Category(module.Category),
|
||||
ID: &module.ID,
|
||||
PluginID: id,
|
||||
Type: module.Type,
|
||||
Category: rpcv1.Category(module.Category),
|
||||
DefaultSpec: module.DefaultSpec,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -67,14 +70,14 @@ func (e EntPluginsRepo) List(ctx context.Context) ([]Plugin, error) {
|
|||
return plugins, nil
|
||||
}
|
||||
|
||||
func (e EntPluginsRepo) UpsertPlugin(ctx context.Context, plugin Plugin) (pluginId uuid.UUID, err error) {
|
||||
func (e EntPluginsRepo) UpsertPlugin(ctx context.Context, p Plugin) (pluginID uuid.UUID, err error) {
|
||||
return e.client.Plugin.
|
||||
Create().
|
||||
SetNillableID(plugin.ID).
|
||||
SetName(plugin.Name).
|
||||
SetLocalPath(plugin.LocalPath).
|
||||
SetURL(plugin.URL.String()).
|
||||
SetHash(plugin.Hash).
|
||||
SetNillableID(p.ID).
|
||||
SetName(p.Name).
|
||||
SetLocalPath(p.LocalPath).
|
||||
SetURL(p.URL.String()).
|
||||
SetHash(p.Hash).
|
||||
OnConflict().
|
||||
UpdateNewValues().
|
||||
ID(ctx)
|
||||
|
@ -88,6 +91,7 @@ func (e EntPluginsRepo) UpsertModules(ctx context.Context, modules []PluginModul
|
|||
SetPluginID(module.PluginID).
|
||||
SetType(module.Type).
|
||||
SetCategory(int(module.Category)).
|
||||
SetDefaultSpec(module.DefaultSpec).
|
||||
OnConflict().
|
||||
UpdateNewValues().
|
||||
Exec(ctx)
|
||||
|
|
|
@ -24,6 +24,8 @@ func (PluginModule) Fields() []ent.Field {
|
|||
MinLen(1),
|
||||
field.Int("category").
|
||||
Min(1),
|
||||
field.Bytes("default_spec").
|
||||
NotEmpty(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,12 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"log/slog"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/sh"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
func (s ScriptTask) Help() (help modules.Help, okay bool) {
|
||||
func (s ScriptTask) Help(context.Context) (help modules.Help, err error) {
|
||||
return modules.Help{
|
||||
Name: "Script - run single commands or complete scripts",
|
||||
Description: `This module helps to run arbitrary commands or complete scripts.
|
||||
|
@ -93,5 +95,5 @@ like changing the current working directory.`,
|
|||
},
|
||||
},
|
||||
},
|
||||
}, true
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -16,8 +16,12 @@ func TestExamples(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := new(task.ScriptTask)
|
||||
for _, e := range s.Help().Examples {
|
||||
help, err := new(task.ScriptTask).Help(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, e := range help.Examples {
|
||||
e := e
|
||||
t.Run(e.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
|
@ -3,11 +3,10 @@ package modules
|
|||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
"testing"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules/state"
|
||||
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
var _ ExecutionContext = (*TestExecutionContext)(nil)
|
||||
|
|
Loading…
Reference in a new issue