feat(packaging): add OCI image creation as package task
This commit is contained in:
parent
72b85dcace
commit
a859b564a9
|
@ -11,8 +11,10 @@ build "go_build" "build_linux" {
|
|||
goarch = each.key
|
||||
|
||||
flags = [
|
||||
"-v",
|
||||
"-trimpath",
|
||||
"-a",
|
||||
"-installsuffix=cgo"
|
||||
]
|
||||
|
||||
ldflags = [
|
||||
|
|
|
@ -11,3 +11,37 @@ package "archive" "linux_amd64" {
|
|||
builds.build_linux_amd64.id = "dist/linux_amd64"
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
package "container_image" "buildr_image" {
|
||||
base_image = "gcr.io/distroless/static"
|
||||
image_name = "code.icb4dc0.de/buildr/buildr"
|
||||
platform = "linux/amd64"
|
||||
|
||||
entrypoint = "/usr/local/bin/buildr"
|
||||
|
||||
tags = [
|
||||
"latest"
|
||||
]
|
||||
|
||||
publish_to_daemon = true
|
||||
publish_to_registry = true
|
||||
|
||||
registry_auth "code.icb4dc0.de" {
|
||||
auth = base64encode(format("prskr:%s", from_vault("gitea_token")))
|
||||
}
|
||||
|
||||
input_mapping = {
|
||||
"${buildr.repo.root}" = "."
|
||||
"${builds.build_linux["amd64"].out_dir}" = "out/"
|
||||
}
|
||||
|
||||
content = {
|
||||
"out/buildr" = "/usr/local/bin/buildr",
|
||||
"README.md" = "/usr/local/man/README.md"
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
builds.build_linux["amd64"].id
|
||||
]
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"github_token":"m1m7a4MCEAvPwwMo:AAAAAAAAAAA=:bHra57FHFNJHqsFIN2JygV3hB70rqa3SMvXSaGR69IbIZ0/mcE5bmQS/HRmdqJVYZPmgI5/VNaw="}
|
||||
{"gitea_token":"0tfC3x/sBkcCUw//:AAAAAAAAAAA=:XQ7xJNmvJgYB1Wq8v7Np9sf1AHCWowbs4usvGYSBAQLqaweLAbXLJCTtZGLjzAV7H+AtMhjD5D8=","github_token":"92+1SdEnrAtwZ2BD:AAAAAAAAAAA=:EcEIm6qUpZqCSPUe0ss48WO5+rwfJQPQ2oV63bPnmIU1Dh2i88CAOkUPMWtW5iGztv22+TSPewA="}
|
||||
|
|
29
go.mod
29
go.mod
|
@ -3,11 +3,14 @@ module code.icb4dc0.de/buildr/buildr
|
|||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/docker/docker v23.0.1+incompatible
|
||||
github.com/google/go-containerregistry v0.14.0
|
||||
github.com/google/go-github/v50 v50.1.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/hanwen/go-fuse/v2 v2.2.0
|
||||
github.com/hashicorp/hcl/v2 v2.16.2
|
||||
github.com/jinzhu/copier v0.3.5
|
||||
github.com/opencontainers/image-spec v1.1.0-rc2
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.15.0
|
||||
|
@ -21,30 +24,46 @@ require (
|
|||
replace golang.org/x/net => golang.org/x/net v0.8.0
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/agext/levenshtein v1.2.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/cli v23.0.1+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.16.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/spf13/afero v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.2 // indirect
|
||||
golang.org/x/net v0.6.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
|
||||
github.com/vbatts/tar-split v0.11.2 // indirect
|
||||
golang.org/x/mod v0.9.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/oauth2 v0.6.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
google.golang.org/protobuf v1.29.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
69
go.sum
69
go.sum
|
@ -36,8 +36,11 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
|||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
|
||||
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||
|
@ -50,10 +53,25 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM=
|
||||
github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY=
|
||||
github.com/docker/docker v23.0.1+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/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
|
@ -67,6 +85,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9
|
|||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
@ -93,8 +113,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
|
@ -109,6 +129,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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.14.0 h1:z58vMqHxuwvAsVwvKEkmVBz2TlgBgH5k6koEXBtlYkw=
|
||||
github.com/google/go-containerregistry v0.14.0/go.mod h1:aiJ2fp/SXvkWgmYHioXnbMdlgB8eXiiYOY55gfN91Wk=
|
||||
github.com/google/go-github/v50 v50.1.0 h1:hMUpkZjklC5GJ+c3GquSqOP/T4BNsB7XohaPhtMOzRk=
|
||||
github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
|
@ -143,13 +165,17 @@ github.com/hashicorp/hcl/v2 v2.16.2 h1:mpkHZh/Tv+xet3sy3F9Ld4FyI2tUpWe9x3XtPx9f1
|
|||
github.com/hashicorp/hcl/v2 v2.16.2/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
|
||||
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
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.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
|
||||
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
|
@ -160,12 +186,21 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3v
|
|||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
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-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
|
@ -173,8 +208,13 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
|
||||
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
|
@ -200,6 +240,9 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
|
|||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
|
||||
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
@ -258,6 +301,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.1/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.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||
golang.org/x/mod v0.9.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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -269,8 +314,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
|
|||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk=
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
|
||||
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -294,6 +339,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -316,6 +362,7 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -335,6 +382,7 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
@ -372,6 +420,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
|
|||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
|
@ -380,10 +429,13 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
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=
|
||||
|
@ -479,11 +531,11 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.29.0 h1:44S3JjaKmLEE4YIkjzexaP+NzZsudE3Zin5Njn/pYX0=
|
||||
google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
@ -491,6 +543,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
30
internal/cmd/args.go
Normal file
30
internal/cmd/args.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
func validArgsFor(moduleType modules.ModuleType) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if len(args) != 0 {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
tasks := maps.Keys(repo.ModulesByType(moduleType))
|
||||
|
||||
filtered := make([]string, 0, len(tasks))
|
||||
|
||||
for i := range tasks {
|
||||
if strings.HasPrefix(tasks[i], toComplete) {
|
||||
filtered = append(filtered, tasks[i])
|
||||
}
|
||||
}
|
||||
|
||||
return filtered, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
}
|
|
@ -2,37 +2,19 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
var buildCmd = &cobra.Command{
|
||||
Use: "build",
|
||||
RunE: runBuild,
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if len(args) != 0 {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
tasks := maps.Keys(repo.Builds())
|
||||
|
||||
filtered := make([]string, 0, len(tasks))
|
||||
|
||||
for i := range tasks {
|
||||
if strings.HasPrefix(tasks[i], toComplete) {
|
||||
filtered = append(filtered, tasks[i])
|
||||
}
|
||||
}
|
||||
|
||||
return filtered, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
Use: "build",
|
||||
RunE: runBuild,
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
ValidArgsFunction: validArgsFor(modules.ModuleTypeBuild),
|
||||
}
|
||||
|
||||
func runBuild(cmd *cobra.Command, args []string) error {
|
||||
|
|
31
internal/cmd/package.go
Normal file
31
internal/cmd/package.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
var packageCmd = &cobra.Command{
|
||||
Use: "package",
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
RunE: runPackage,
|
||||
ValidArgsFunction: validArgsFor(modules.ModuleTypePackage),
|
||||
}
|
||||
|
||||
func runPackage(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("no package specified")
|
||||
}
|
||||
|
||||
plan, err := modules.NewExecutionPlanFor(modules.ModuleTypePackage, args[0], repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return plan.Execute(cmd.Context(), repo.Buildr)
|
||||
}
|
|
@ -16,6 +16,7 @@ import (
|
|||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/build"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/buildr"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/packaging"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/task"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/tool"
|
||||
)
|
||||
|
@ -38,7 +39,7 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(toolCmd, taskCmd, buildCmd, vaultCmd)
|
||||
rootCmd.AddCommand(toolCmd, taskCmd, buildCmd, packageCmd, vaultCmd)
|
||||
rootCmd.PersistentFlags().StringVar(&buildRDir, "buildR-dir", ".buildr", "Directory where to look for BuildR files - if relative path will be relavtive to repository root (where the next .git directory resides")
|
||||
rootCmd.PersistentFlags().String("vault-passphrase", "", "Password for vault - has precedence over vault-passphrase-file")
|
||||
rootCmd.PersistentFlags().String("vault-passphrase-file", "", "File containing the vault passphrase")
|
||||
|
@ -93,11 +94,12 @@ func initBuildR(cmd *cobra.Command, _ []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
registry := modules.NewRegistry()
|
||||
|
||||
build.RegisterTypes(registry)
|
||||
tool.RegisterTypes(registry)
|
||||
task.RegisterTypes(registry)
|
||||
registry := modules.NewRegistry(
|
||||
build.Registration,
|
||||
tool.Registration,
|
||||
task.Registration,
|
||||
packaging.Registration,
|
||||
)
|
||||
|
||||
buildrInstance, err = rawSpec.Config.Buildr(buildRDir, repoRoot)
|
||||
if err != nil {
|
||||
|
|
|
@ -2,37 +2,19 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
var taskCmd = &cobra.Command{
|
||||
Use: "task",
|
||||
RunE: runTask,
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if len(args) != 0 {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
tasks := maps.Keys(repo.Tasks())
|
||||
|
||||
filtered := make([]string, 0, len(tasks))
|
||||
|
||||
for i := range tasks {
|
||||
if strings.HasPrefix(tasks[i], toComplete) {
|
||||
filtered = append(filtered, tasks[i])
|
||||
}
|
||||
}
|
||||
|
||||
return filtered, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
Use: "task",
|
||||
RunE: runTask,
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
ValidArgsFunction: validArgsFor(modules.ModuleTypeTask),
|
||||
}
|
||||
|
||||
func runTask(cmd *cobra.Command, args []string) error {
|
||||
|
|
|
@ -2,37 +2,19 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
var toolCmd = &cobra.Command{
|
||||
Use: "tool",
|
||||
RunE: runTool,
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if len(args) != 0 {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
tasks := maps.Keys(repo.Tools())
|
||||
|
||||
filtered := make([]string, 0, len(tasks))
|
||||
|
||||
for i := range tasks {
|
||||
if strings.HasPrefix(tasks[i], toComplete) {
|
||||
filtered = append(filtered, tasks[i])
|
||||
}
|
||||
}
|
||||
|
||||
return filtered, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
Use: "tool",
|
||||
RunE: runTool,
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
ValidArgsFunction: validArgsFor(modules.ModuleTypeTool),
|
||||
}
|
||||
|
||||
func runTool(cmd *cobra.Command, args []string) error {
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
package parsing
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
var _ modules.Block = (*BuildBlock)(nil)
|
||||
|
||||
type BuildBlock struct {
|
||||
BuildType string `hcl:",label"`
|
||||
BuildName string `hcl:",label"`
|
||||
Remain hcl.Body `hcl:",remain"`
|
||||
}
|
||||
|
||||
func (b BuildBlock) Type() modules.ModuleType {
|
||||
return modules.ModuleTypeBuild
|
||||
}
|
||||
|
||||
func (b BuildBlock) Name() string {
|
||||
return b.BuildName
|
||||
}
|
||||
|
||||
func (b BuildBlock) Body() hcl.Body {
|
||||
return b.Remain
|
||||
}
|
||||
|
||||
func (b BuildBlock) Module() string {
|
||||
return b.BuildType
|
||||
}
|
|
@ -92,9 +92,9 @@ func prepareBlockForParsing(block modules.Block, evalCtx *hcl.EvalContext, build
|
|||
|
||||
gb := GenericBlock{
|
||||
blockType: block.Type(),
|
||||
moduleName: block.Module(),
|
||||
name: blockName,
|
||||
body: initBlock(blockCopy, block.Type(), blockName, buildrInstance.Config.OutDirectory),
|
||||
ModuleName: block.Module(),
|
||||
BlockName: blockName,
|
||||
BlockBody: initBlock(blockCopy, block.Type(), blockName, buildrInstance.Config.OutDirectory),
|
||||
}
|
||||
|
||||
result.Specs = append(result.Specs, parsingSpecOf(gb, vals))
|
||||
|
|
|
@ -8,15 +8,29 @@ import (
|
|||
|
||||
var _ modules.Block = (*GenericBlock)(nil)
|
||||
|
||||
type GenericBlocks []GenericBlock
|
||||
|
||||
func (b GenericBlocks) Blocks() []GenericBlock {
|
||||
return b
|
||||
}
|
||||
|
||||
func (b GenericBlocks) WithType(blockType modules.ModuleType) GenericBlocks {
|
||||
for i := range b {
|
||||
b[i].blockType = blockType
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
type GenericBlock struct {
|
||||
blockType modules.ModuleType
|
||||
moduleName string
|
||||
name string
|
||||
body hcl.Body
|
||||
ModuleName string `hcl:",label"`
|
||||
BlockName string `hcl:",label"`
|
||||
BlockBody hcl.Body `hcl:",remain"`
|
||||
}
|
||||
|
||||
func (g GenericBlock) Module() string {
|
||||
return g.moduleName
|
||||
return g.ModuleName
|
||||
}
|
||||
|
||||
func (g GenericBlock) Type() modules.ModuleType {
|
||||
|
@ -24,9 +38,9 @@ func (g GenericBlock) Type() modules.ModuleType {
|
|||
}
|
||||
|
||||
func (g GenericBlock) Name() string {
|
||||
return g.name
|
||||
return g.BlockName
|
||||
}
|
||||
|
||||
func (g GenericBlock) Body() hcl.Body {
|
||||
return g.body
|
||||
return g.BlockBody
|
||||
}
|
||||
|
|
|
@ -12,11 +12,12 @@ import (
|
|||
)
|
||||
|
||||
type RawSpec struct {
|
||||
Config BuildrConfig `hcl:"buildr,block"`
|
||||
Locals []LocalsBlock `hcl:"locals,block"`
|
||||
Tools []ToolBlock `hcl:"tool,block"`
|
||||
Tasks []TaskBlock `hcl:"task,block"`
|
||||
Builds []BuildBlock `hcl:"build,block"`
|
||||
Config BuildrConfig `hcl:"buildr,block"`
|
||||
Locals []LocalsBlock `hcl:"locals,block"`
|
||||
Tools GenericBlocks `hcl:"tool,block"`
|
||||
Tasks GenericBlocks `hcl:"task,block"`
|
||||
Builds GenericBlocks `hcl:"build,block"`
|
||||
Packages GenericBlocks `hcl:"package,block"`
|
||||
}
|
||||
|
||||
func (s RawSpec) Repository(ctx context.Context, b buildr.Buildr, svc *services.Collection) (repo *modules.Repository, err error) {
|
||||
|
@ -36,19 +37,25 @@ func (s RawSpec) Repository(ctx context.Context, b buildr.Buildr, svc *services.
|
|||
|
||||
parsingSpecs := make([]blockParsingSpec, 0, len(s.Tools)+len(s.Tasks)+len(s.Builds))
|
||||
|
||||
if specs, err := s.buildParsingInventory(toBlocks(s.Tools), "tools", evalCtx, b); err != nil {
|
||||
if specs, err := s.buildParsingInventory(toBlocks(s.Tools.WithType(modules.ModuleTypeTool)), evalCtx, b); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
parsingSpecs = append(parsingSpecs, specs...)
|
||||
}
|
||||
|
||||
if specs, err := s.buildParsingInventory(toBlocks(s.Tasks), "tasks", evalCtx, b); err != nil {
|
||||
if specs, err := s.buildParsingInventory(toBlocks(s.Tasks.WithType(modules.ModuleTypeTask)), evalCtx, b); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
parsingSpecs = append(parsingSpecs, specs...)
|
||||
}
|
||||
|
||||
if specs, err := s.buildParsingInventory(toBlocks(s.Builds), "builds", evalCtx, b); err != nil {
|
||||
if specs, err := s.buildParsingInventory(toBlocks(s.Builds.WithType(modules.ModuleTypeBuild)), evalCtx, b); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
parsingSpecs = append(parsingSpecs, specs...)
|
||||
}
|
||||
|
||||
if specs, err := s.buildParsingInventory(toBlocks(s.Packages.WithType(modules.ModuleTypePackage)), evalCtx, b); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
parsingSpecs = append(parsingSpecs, specs...)
|
||||
|
@ -65,10 +72,16 @@ func (s RawSpec) Repository(ctx context.Context, b buildr.Buildr, svc *services.
|
|||
|
||||
func (s RawSpec) buildParsingInventory(
|
||||
blocks []modules.Block,
|
||||
groupName string,
|
||||
evalCtx *hcl.EvalContext,
|
||||
buildrInstance buildr.Buildr,
|
||||
) ([]blockParsingSpec, error) {
|
||||
|
||||
if len(blocks) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
groupName := blocks[0].Type().GroupName()
|
||||
|
||||
blockGroupRepresentation := make(map[string]cty.Value, len(blocks))
|
||||
blockGroupParsingSpecs := make([]blockParsingSpec, 0)
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
package parsing
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
var _ modules.Block = (*TaskBlock)(nil)
|
||||
|
||||
type TaskBlock struct {
|
||||
TaskType string `hcl:",label"`
|
||||
TaskName string `hcl:",label"`
|
||||
Remain hcl.Body `hcl:",remain"`
|
||||
}
|
||||
|
||||
func (b TaskBlock) Type() modules.ModuleType {
|
||||
return modules.ModuleTypeTask
|
||||
}
|
||||
|
||||
func (b TaskBlock) Name() string {
|
||||
return b.TaskName
|
||||
}
|
||||
|
||||
func (b TaskBlock) Body() hcl.Body {
|
||||
return b.Remain
|
||||
}
|
||||
|
||||
func (b TaskBlock) Module() string {
|
||||
return b.TaskType
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package parsing
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
var _ modules.Block = (*ToolBlock)(nil)
|
||||
|
||||
type ToolBlock struct {
|
||||
ToolType string `hcl:",label"`
|
||||
ToolName string `hcl:",label"`
|
||||
Remain hcl.Body `hcl:",remain"`
|
||||
}
|
||||
|
||||
func (b ToolBlock) Type() modules.ModuleType {
|
||||
return modules.ModuleTypeTool
|
||||
}
|
||||
|
||||
func (b ToolBlock) Name() string {
|
||||
return b.ToolName
|
||||
}
|
||||
|
||||
func (b ToolBlock) Body() hcl.Body {
|
||||
return b.Remain
|
||||
}
|
||||
|
||||
func (b ToolBlock) Module() string {
|
||||
return b.ToolType
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
package modules
|
||||
|
||||
type BaseModule struct {
|
||||
Id string `hcl:"id,optional"`
|
||||
OutputDir string `hcl:"out_dir,optional"`
|
||||
Name string `hcl:"name,optional"`
|
||||
RepoIsolation bool `hcl:"repo_isolation,optional"`
|
||||
Deps []string `hcl:"depends_on,optional"`
|
||||
InputMapping map[string]string `hcl:"input_mapping,optional"`
|
||||
Id string `hcl:"id,optional"`
|
||||
OutputDir string `hcl:"out_dir,optional"`
|
||||
Name string `hcl:"name,optional"`
|
||||
Deps []string `hcl:"depends_on,optional"`
|
||||
InputMapping map[string]string `hcl:"input_mapping,optional"`
|
||||
}
|
||||
|
||||
func (m BaseModule) ModuleName() string {
|
||||
|
|
|
@ -21,19 +21,15 @@ type GoBuild struct {
|
|||
Main string `hcl:"main"`
|
||||
GoOS string `hcl:"goos"`
|
||||
GoArch string `hcl:"goarch"`
|
||||
Flags []string `hcl:"flags"`
|
||||
LdFlags []string `hcl:"ldflags"`
|
||||
Env map[string]string `hcl:"env"`
|
||||
Flags []string `hcl:"flags,optional"`
|
||||
LdFlags []string `hcl:"ldflags,optional"`
|
||||
Env map[string]string `hcl:"env,optional"`
|
||||
}
|
||||
|
||||
func (g GoBuild) Type() modules.ModuleType {
|
||||
return modules.ModuleTypeBuild
|
||||
}
|
||||
|
||||
func (g GoBuild) ModuleName() string {
|
||||
return g.Name
|
||||
}
|
||||
|
||||
func (g GoBuild) Execute(ctx modules.ExecutionContext) (err error) {
|
||||
logger := ctx.Logger()
|
||||
|
||||
|
@ -69,10 +65,14 @@ func (g GoBuild) Execute(ctx modules.ExecutionContext) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
cmd.AddEnv(map[string]string{
|
||||
"GOARCH": g.GoArch,
|
||||
"GOOS": g.GoOS,
|
||||
})
|
||||
if g.Env == nil {
|
||||
g.Env = make(map[string]string, 2)
|
||||
}
|
||||
|
||||
g.Env["GOARCH"] = g.GoArch
|
||||
g.Env["GOOS"] = g.GoOS
|
||||
|
||||
cmd.AddEnv(g.Env)
|
||||
|
||||
defer func() {
|
||||
err = errors.Join(err, cmd.Close())
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
func RegisterTypes(registry *modules.TypeRegistry) {
|
||||
var Registration = modules.RegistrationFunc(func(registry *modules.TypeRegistry) {
|
||||
registry.RegisterModule(modules.ModuleTypeBuild, "go_build", modules.ModuleFactoryFunc(func(block modules.Block, hclCtx *hcl.EvalContext) (modules.Module, error) {
|
||||
b := new(GoBuild)
|
||||
diags := gohcl.DecodeBody(block.Body(), hclCtx, b)
|
||||
|
@ -19,4 +19,4 @@ func RegisterTypes(registry *modules.TypeRegistry) {
|
|||
|
||||
return b, nil
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
|
25
modules/helpers/strings/base64.go
Normal file
25
modules/helpers/strings/base64.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package strings
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
)
|
||||
|
||||
func Base64Encode() function.Function {
|
||||
return function.New(&function.Spec{
|
||||
Description: "Encode a string as base64",
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "input",
|
||||
Description: "input string to be encoded as base64",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
||||
return cty.StringVal(base64.StdEncoding.EncodeToString([]byte(args[0].AsString()))), nil
|
||||
},
|
||||
})
|
||||
}
|
61
modules/helpers/strings/format.go
Normal file
61
modules/helpers/strings/format.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package strings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
)
|
||||
|
||||
func Format() function.Function {
|
||||
return function.New(&function.Spec{
|
||||
Description: "Format a string",
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "format",
|
||||
Description: "format for the resulting string",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
VarParam: &function.Parameter{
|
||||
Name: "args",
|
||||
Description: "variadic args for format",
|
||||
Type: cty.DynamicPseudoType,
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
||||
format := args[0].AsString()
|
||||
formatArgs := make([]any, 0, len(args))
|
||||
|
||||
if len(args) > 1 {
|
||||
for i := 1; i < len(args); i++ {
|
||||
if unboxed := unbox(args[i]); unboxed != nil {
|
||||
formatArgs = append(formatArgs, unboxed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cty.StringVal(fmt.Sprintf(format, formatArgs...)), nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func unbox(in cty.Value) any {
|
||||
switch in.Type() {
|
||||
case cty.String:
|
||||
return in.AsString()
|
||||
case cty.Number:
|
||||
bigFloat := in.AsBigFloat()
|
||||
if bigFloat.IsInt() {
|
||||
i, _ := bigFloat.Int64()
|
||||
return i
|
||||
} else {
|
||||
f, _ := bigFloat.Float64()
|
||||
return f
|
||||
}
|
||||
case cty.Bool:
|
||||
return in.True()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -4,4 +4,6 @@ import "github.com/hashicorp/hcl/v2"
|
|||
|
||||
func RegisterInContext(evalCtx *hcl.EvalContext) {
|
||||
evalCtx.Functions["trim"] = Trim()
|
||||
evalCtx.Functions["format"] = Format()
|
||||
evalCtx.Functions["base64encode"] = Base64Encode()
|
||||
}
|
||||
|
|
94
modules/packaging/ociimg/daemon_publisher.go
Normal file
94
modules/packaging/ociimg/daemon_publisher.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
package ociimg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/daemon"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
func newContainerDaemon(imageName string, logger *slog.Logger, tags []string, cli daemon.Client) containerDaemon {
|
||||
return containerDaemon{
|
||||
imageName: imageName,
|
||||
logger: logger,
|
||||
client: cli,
|
||||
tags: tags,
|
||||
}
|
||||
}
|
||||
|
||||
type containerDaemon struct {
|
||||
imageName string
|
||||
logger *slog.Logger
|
||||
client daemon.Client
|
||||
tags []string
|
||||
}
|
||||
|
||||
func (d containerDaemon) Publish(ctx context.Context, result imageOrIndex) (name.Reference, error) {
|
||||
if len(d.tags) == 0 {
|
||||
return nil, errors.New("at least one tag must be specified")
|
||||
}
|
||||
|
||||
var img v1.Image
|
||||
switch i := result.(type) {
|
||||
case v1.Image:
|
||||
img = i
|
||||
case v1.ImageIndex:
|
||||
im, err := i.IndexManifest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(im.Manifests) < 1 {
|
||||
return nil, errors.New("index is empty")
|
||||
}
|
||||
|
||||
img, err = i.Image(im.Manifests[0].Digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("failed to interpret %s result as image: %v", d.imageName, result)
|
||||
}
|
||||
|
||||
defaultTag, err := name.NewTag(fmt.Sprintf("%s:%s", d.imageName, d.tags[0]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.logger.Info("Loading", slog.Any("defaultTag", defaultTag))
|
||||
|
||||
if resp, err := daemon.Write(defaultTag, img, d.getOpts(ctx)...); err != nil {
|
||||
d.logger.Debug("daemon.Write", slog.String("response", resp))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.logger.Info("Loaded", slog.Any("defaultTag", defaultTag))
|
||||
|
||||
for _, tagName := range d.tags[1:] {
|
||||
d.logger.Info("Adding tag", slog.String("tag", tagName))
|
||||
|
||||
tag, err := name.NewTag(fmt.Sprintf("%s:%s", d.imageName, tagName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := daemon.Tag(defaultTag, tag, d.getOpts(ctx)...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.logger.Info("Added tag", slog.String("tag", tagName))
|
||||
}
|
||||
|
||||
return &defaultTag, nil
|
||||
}
|
||||
|
||||
func (d containerDaemon) getOpts(ctx context.Context) []daemon.Option {
|
||||
return []daemon.Option{
|
||||
daemon.WithContext(ctx),
|
||||
daemon.WithClient(d.client),
|
||||
}
|
||||
}
|
47
modules/packaging/ociimg/helpers.go
Normal file
47
modules/packaging/ociimg/helpers.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package ociimg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
)
|
||||
|
||||
func imageFromIndex(index v1.ImageIndex, platform *v1.Platform) (v1.Image, v1.Descriptor, error) {
|
||||
im, err := index.IndexManifest()
|
||||
if err != nil {
|
||||
return nil, v1.Descriptor{}, err
|
||||
}
|
||||
|
||||
for i := range im.Manifests {
|
||||
manifest := im.Manifests[i]
|
||||
if manifest.MediaType != types.OCIManifestSchema1 && im.MediaType != types.DockerManifestSchema2 {
|
||||
return nil, v1.Descriptor{}, fmt.Errorf("%q has unexpected mediaType %q in base for %q", manifest.Digest, manifest.MediaType, platform)
|
||||
}
|
||||
if manifest.Platform.Satisfies(*platform) {
|
||||
img, err := index.Image(manifest.Digest)
|
||||
return img, manifest, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, v1.Descriptor{}, fmt.Errorf("index does not contain image satisfying the requested platoform %q", platform)
|
||||
}
|
||||
|
||||
func fetch(ctx context.Context, ref name.Reference) (imageOrIndex, error) {
|
||||
ropt := []remote.Option{
|
||||
remote.WithUserAgent(userAgent),
|
||||
remote.WithContext(ctx),
|
||||
}
|
||||
|
||||
desc, err := remote.Get(ref, ropt...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if desc.MediaType.IsIndex() {
|
||||
return desc.ImageIndex()
|
||||
}
|
||||
return desc.Image()
|
||||
}
|
318
modules/packaging/ociimg/oci_image.go
Normal file
318
modules/packaging/ociimg/oci_image.go
Normal file
|
@ -0,0 +1,318 @@
|
|||
package ociimg
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
"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"
|
||||
"golang.org/x/exp/slog"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
var (
|
||||
_ modules.Module = (*ContainerImage)(nil)
|
||||
defaultCreationTime = time.Unix(0, 0)
|
||||
)
|
||||
|
||||
type ContainerImage struct {
|
||||
modules.BaseModule `hcl:",remain"`
|
||||
BaseImage string `hcl:"base_image"`
|
||||
ImageName string `hcl:"image_name"`
|
||||
Tags []string `hcl:"tags"`
|
||||
Platform string `hcl:"platform"`
|
||||
Entrypoint *string `hcl:"entrypoint,optional"`
|
||||
Command []string `hcl:"command,optional"`
|
||||
Content map[string]string `hcl:"content"`
|
||||
PublishToDaemon bool `hcl:"publish_to_daemon,optional"`
|
||||
PublishToRegistry bool `hcl:"publish_to_registry,optional"`
|
||||
RegistryCredentials []RegistryAuth `hcl:"registry_auth,block"`
|
||||
|
||||
cache sync.Map
|
||||
publishers []Publisher
|
||||
}
|
||||
|
||||
func (o *ContainerImage) Type() modules.ModuleType {
|
||||
return modules.ModuleTypePackage
|
||||
}
|
||||
|
||||
func (o *ContainerImage) Execute(ctx modules.ExecutionContext) error {
|
||||
logger := ctx.Logger()
|
||||
|
||||
if err := o.initPublishers(logger); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
baseRef, base, err := o.getBaseImage(ctx, logger, o.BaseImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mt, err := base.MediaType()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Annotate the base image we pass to the build function with
|
||||
// annotations indicating the digest (and possibly tag) of the
|
||||
// base image. This will be inherited by the image produced.
|
||||
if mt != types.DockerManifestList {
|
||||
baseDigest, err := base.Digest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
anns := map[string]string{
|
||||
specsv1.AnnotationBaseImageDigest: baseDigest.String(),
|
||||
specsv1.AnnotationBaseImageName: baseRef.Name(),
|
||||
}
|
||||
base = mutate.Annotations(base, anns).(imageOrIndex)
|
||||
}
|
||||
|
||||
platform, err := v1.ParsePlatform(o.Platform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var buildResult imageOrIndex
|
||||
|
||||
switch mt {
|
||||
case types.OCIImageIndex, types.DockerManifestList:
|
||||
baseIdx, ok := base.(v1.ImageIndex)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to interpret base as index: %v", base)
|
||||
}
|
||||
|
||||
im, err := baseIdx.IndexManifest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
img, desc, err := imageFromIndex(baseIdx, platform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
img = mutate.Annotations(img, map[string]string{
|
||||
specsv1.AnnotationBaseImageDigest: desc.Digest.String(),
|
||||
specsv1.AnnotationBaseImageName: baseRef.Name(),
|
||||
}).(v1.Image)
|
||||
|
||||
builtImage, err := o.buildImage(ctx, img, platform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
adds := mutate.IndexAddendum{
|
||||
Add: builtImage,
|
||||
Descriptor: v1.Descriptor{
|
||||
URLs: desc.URLs,
|
||||
MediaType: desc.MediaType,
|
||||
Annotations: desc.Annotations,
|
||||
Platform: desc.Platform,
|
||||
},
|
||||
}
|
||||
|
||||
buildResult = mutate.AppendManifests(
|
||||
mutate.Annotations(
|
||||
mutate.IndexMediaType(empty.Index, mt),
|
||||
im.Annotations,
|
||||
).(v1.ImageIndex),
|
||||
adds,
|
||||
)
|
||||
|
||||
case types.OCIManifestSchema1, types.DockerManifestSchema2:
|
||||
baseImage, ok := base.(v1.Image)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to interpret base as image: %v", base)
|
||||
}
|
||||
|
||||
buildResult, err = o.buildImage(ctx, baseImage, platform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := range o.publishers {
|
||||
if _, err := o.publishers[i].Publish(ctx, buildResult); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ContainerImage) initPublishers(logger *slog.Logger) error {
|
||||
if o.PublishToDaemon {
|
||||
cli, err := client.NewClientWithOpts(
|
||||
client.WithHostFromEnv(),
|
||||
client.WithTLSClientConfigFromEnv(),
|
||||
client.WithVersionFromEnv(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.publishers = append(o.publishers, newContainerDaemon(o.ImageName, logger, o.Tags, cli))
|
||||
}
|
||||
|
||||
if o.PublishToRegistry {
|
||||
opts := []registryPublisherOption{
|
||||
withTags(o.Tags...),
|
||||
}
|
||||
if o.RegistryCredentials != nil {
|
||||
opts = append(opts, withKeyChain(authn.NewMultiKeychain(authn.DefaultKeychain, KeyChain(o.RegistryCredentials))))
|
||||
}
|
||||
o.publishers = append(o.publishers, newRegistryPublisher(o.ImageName, logger, opts...))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ContainerImage) buildImage(ctx modules.ExecutionContext, base v1.Image, platform *v1.Platform) (v1.Image, error) {
|
||||
// Layers should be typed to match the underlying image, since some
|
||||
// registries reject mixed-type layers.
|
||||
var layerMediaType types.MediaType
|
||||
mt, err := base.MediaType()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch mt {
|
||||
case types.OCIManifestSchema1:
|
||||
layerMediaType = types.OCILayer
|
||||
case types.DockerManifestSchema2:
|
||||
layerMediaType = types.DockerLayer
|
||||
}
|
||||
|
||||
if err := o.platformMatches(platform); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
contentTemp, err := os.CreateTemp(os.TempDir(), "buildr-oci-image-")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
tempFilePath := contentTemp.Name()
|
||||
_ = contentTemp.Close()
|
||||
_ = os.Remove(tempFilePath)
|
||||
}()
|
||||
|
||||
if err := o.tarFiles(contentTemp, ctx.Buildr().Repo.Root); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
layer, err := tarball.LayerFromOpener(func() (io.ReadCloser, error) {
|
||||
if _, err := contentTemp.Seek(0, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return io.NopCloser(contentTemp), nil
|
||||
}, tarball.WithCompressedCaching, tarball.WithMediaType(layerMediaType))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
withContent, err := mutate.Append(base, mutate.Addendum{
|
||||
Layer: layer,
|
||||
History: v1.History{
|
||||
Author: "buildr",
|
||||
CreatedBy: fmt.Sprintf("oci_image %s", o.Name),
|
||||
Created: v1.Time{Time: defaultCreationTime},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg, err := withContent.ConfigFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg = cfg.DeepCopy()
|
||||
|
||||
if o.Entrypoint != nil {
|
||||
cfg.Config.Entrypoint = []string{*o.Entrypoint}
|
||||
}
|
||||
|
||||
cfg.Config.Cmd = o.Command
|
||||
cfg.Author = "buildr"
|
||||
|
||||
if cfg.Config.Labels == nil {
|
||||
cfg.Config.Labels = map[string]string{}
|
||||
}
|
||||
|
||||
return mutate.ConfigFile(withContent, cfg)
|
||||
}
|
||||
|
||||
func (o *ContainerImage) tarFiles(outWriter io.Writer, cwd string) error {
|
||||
tw := tar.NewWriter(outWriter)
|
||||
defer tw.Close()
|
||||
|
||||
tree, err := buildDirFromContent(cwd, o.Content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tree.writeToTar(tw, "/")
|
||||
}
|
||||
|
||||
func (o *ContainerImage) platformMatches(platform *v1.Platform) error {
|
||||
parsed, err := v1.ParsePlatform(o.Platform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if parsed.Satisfies(*platform) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("platform %s does not satisfy %s", platform.String(), o.Platform)
|
||||
}
|
||||
|
||||
func (o *ContainerImage) getBaseImage(ctx context.Context, logger *slog.Logger, imageRef string) (name.Reference, imageOrIndex, error) {
|
||||
ref, err := name.ParseReference(imageRef, name.WithDefaultRegistry("docker.io"))
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("parsing base image (%q): %w", imageRef, err)
|
||||
}
|
||||
|
||||
if v, ok := o.cache.Load(ref.String()); ok {
|
||||
return ref, v.(imageOrIndex), nil
|
||||
}
|
||||
|
||||
result, err := fetch(ctx, ref)
|
||||
if err != nil {
|
||||
return ref, result, err
|
||||
}
|
||||
|
||||
if dig, ok := ref.(name.Digest); ok {
|
||||
logger.Info("Using base", slog.String("base_image", fmt.Sprintf("%s@%s", ref, dig)))
|
||||
} else {
|
||||
dig, err := result.Digest()
|
||||
if err != nil {
|
||||
return ref, result, err
|
||||
}
|
||||
logger.Info("Using base", slog.String("base_image", fmt.Sprintf("%s@%s", ref, dig)))
|
||||
}
|
||||
|
||||
o.cache.Store(ref.String(), result)
|
||||
return ref, result, nil
|
||||
}
|
24
modules/packaging/ociimg/publishing.go
Normal file
24
modules/packaging/ociimg/publishing.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package ociimg
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
)
|
||||
|
||||
const (
|
||||
latestTag = "latest"
|
||||
userAgent = "buildr"
|
||||
)
|
||||
|
||||
type imageOrIndex interface {
|
||||
RawManifest() ([]byte, error)
|
||||
MediaType() (types.MediaType, error)
|
||||
Digest() (v1.Hash, error)
|
||||
}
|
||||
|
||||
type Publisher interface {
|
||||
Publish(ctx context.Context, result imageOrIndex) (name.Reference, error)
|
||||
}
|
56
modules/packaging/ociimg/registry_auth.go
Normal file
56
modules/packaging/ociimg/registry_auth.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package ociimg
|
||||
|
||||
import "github.com/google/go-containerregistry/pkg/authn"
|
||||
|
||||
var (
|
||||
_ authn.Keychain = (*BuildrKeyChain)(nil)
|
||||
_ authn.Authenticator = (*AuthConfig)(nil)
|
||||
)
|
||||
|
||||
type RegistryAuth struct {
|
||||
Registry string `hcl:",label"`
|
||||
AuthConfig `hcl:",remain"`
|
||||
}
|
||||
|
||||
func KeyChain(creds []RegistryAuth) BuildrKeyChain {
|
||||
chain := make(BuildrKeyChain)
|
||||
for i := range creds {
|
||||
c := creds[i]
|
||||
chain[c.Registry] = c.AuthConfig
|
||||
}
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
type BuildrKeyChain map[string]AuthConfig
|
||||
|
||||
func (b BuildrKeyChain) Resolve(resource authn.Resource) (authn.Authenticator, error) {
|
||||
if cfg, ok := b[resource.RegistryStr()]; !ok {
|
||||
return authn.Anonymous, nil
|
||||
} else {
|
||||
return cfg, nil
|
||||
}
|
||||
}
|
||||
|
||||
type AuthConfig struct {
|
||||
Username string `hcl:"username,optional"`
|
||||
Password string `hcl:"password,optional"`
|
||||
Auth string `hcl:"auth,optional"`
|
||||
|
||||
// IdentityToken is used to authenticate the user and get
|
||||
// an access token for the registry.
|
||||
IdentityToken string `hcl:"identitytoken,optional"`
|
||||
|
||||
// RegistryToken is a bearer token to be sent to a registry
|
||||
RegistryToken string `hcl:"registrytoken,optional"`
|
||||
}
|
||||
|
||||
func (a AuthConfig) Authorization() (*authn.AuthConfig, error) {
|
||||
return &authn.AuthConfig{
|
||||
Username: a.Username,
|
||||
Password: a.Password,
|
||||
Auth: a.Auth,
|
||||
IdentityToken: a.IdentityToken,
|
||||
RegistryToken: a.RegistryToken,
|
||||
}, nil
|
||||
}
|
154
modules/packaging/ociimg/registry_publisher.go
Normal file
154
modules/packaging/ociimg/registry_publisher.go
Normal file
|
@ -0,0 +1,154 @@
|
|||
package ociimg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
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"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
type registryPublisherOption func(p *registryPublisher)
|
||||
|
||||
func withTags(tags ...string) registryPublisherOption {
|
||||
return func(p *registryPublisher) {
|
||||
tagsSet := make(map[string]bool)
|
||||
for i := range p.tags {
|
||||
tagsSet[p.tags[i]] = true
|
||||
}
|
||||
|
||||
for i := range tags {
|
||||
tagsSet[tags[i]] = true
|
||||
}
|
||||
|
||||
p.tags = maps.Keys(tagsSet)
|
||||
}
|
||||
}
|
||||
|
||||
func withTransport(t http.RoundTripper) registryPublisherOption {
|
||||
return func(p *registryPublisher) {
|
||||
p.t = t
|
||||
}
|
||||
}
|
||||
|
||||
func withInsecure(insecure bool) registryPublisherOption {
|
||||
return func(p *registryPublisher) {
|
||||
p.insecure = insecure
|
||||
}
|
||||
}
|
||||
|
||||
func withKeyChain(kc authn.Keychain) registryPublisherOption {
|
||||
return func(p *registryPublisher) {
|
||||
p.keychain = kc
|
||||
}
|
||||
}
|
||||
|
||||
func newRegistryPublisher(
|
||||
imageName string,
|
||||
logger *slog.Logger,
|
||||
opts ...registryPublisherOption,
|
||||
) registryPublisher {
|
||||
p := registryPublisher{
|
||||
imageName: imageName,
|
||||
logger: logger,
|
||||
tags: []string{latestTag},
|
||||
t: http.DefaultTransport,
|
||||
keychain: authn.DefaultKeychain,
|
||||
}
|
||||
|
||||
for i := range opts {
|
||||
opts[i](&p)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
type registryPublisher struct {
|
||||
imageName string
|
||||
logger *slog.Logger
|
||||
tags []string
|
||||
t http.RoundTripper
|
||||
keychain authn.Keychain
|
||||
insecure bool
|
||||
}
|
||||
|
||||
func (p registryPublisher) Publish(ctx context.Context, result imageOrIndex) (name.Reference, error) {
|
||||
ro := []remote.Option{
|
||||
remote.WithAuthFromKeychain(p.keychain),
|
||||
remote.WithTransport(p.t),
|
||||
remote.WithContext(ctx),
|
||||
remote.WithUserAgent(userAgent),
|
||||
}
|
||||
|
||||
var no []name.Option
|
||||
if p.insecure {
|
||||
no = append(no, name.Insecure)
|
||||
}
|
||||
|
||||
for i, tagName := range p.tags {
|
||||
tag, err := name.NewTag(fmt.Sprintf("%s:%s", p.imageName, tagName), no...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
p.logger.Debug("Publishing", slog.String("tag", tag.String()))
|
||||
if err := pushResult(tag, result, ro); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
p.logger.Debug("Tagging", slog.String("tag", tag.String()))
|
||||
if err := remote.Tag(tag, result, ro...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h, err := result.Digest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ref := fmt.Sprintf("%s@%s", p.imageName, h)
|
||||
if len(p.tags) == 1 && p.tags[0] != latestTag {
|
||||
// If a single tag is explicitly set (not latest), then this
|
||||
// is probably a release, so include the tag in the reference.
|
||||
ref = fmt.Sprintf("%s:%s@%s", p.imageName, p.tags[0], h)
|
||||
}
|
||||
dig, err := name.NewDigest(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.logger.Debug("Published", slog.String("digest", dig.String()))
|
||||
return &dig, nil
|
||||
}
|
||||
|
||||
func pushResult(tag name.Tag, br imageOrIndex, opt []remote.Option) error {
|
||||
mt, err := br.MediaType()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch mt {
|
||||
case types.OCIImageIndex, types.DockerManifestList:
|
||||
idx, ok := br.(v1.ImageIndex)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to interpret result as index: %v", br)
|
||||
}
|
||||
|
||||
return remote.WriteIndex(tag, idx, opt...)
|
||||
case types.OCIManifestSchema1, types.DockerManifestSchema2:
|
||||
img, ok := br.(v1.Image)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to interpret result as image: %v", br)
|
||||
}
|
||||
return remote.Write(tag, img, opt...)
|
||||
default:
|
||||
return fmt.Errorf("result image media type: %s", mt)
|
||||
}
|
||||
}
|
169
modules/packaging/ociimg/tar.go
Normal file
169
modules/packaging/ociimg/tar.go
Normal file
|
@ -0,0 +1,169 @@
|
|||
package ociimg
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func buildDirFromContent(cwd string, content map[string]string) (*dirNode, error) {
|
||||
rootNode := newDirNode()
|
||||
for source, target := range content {
|
||||
if !filepath.IsAbs(source) {
|
||||
source = filepath.Join(cwd, source)
|
||||
}
|
||||
|
||||
info, err := os.Stat(source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
walkErr := filepath.WalkDir(source, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
rootNode.addDir(path)
|
||||
} else {
|
||||
rootNode.addFile(path, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if walkErr != nil {
|
||||
return nil, walkErr
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(target, "/") {
|
||||
_, fileName := filepath.Split(source)
|
||||
target = filepath.Join(target, fileName)
|
||||
}
|
||||
|
||||
rootNode.addFile(source, target)
|
||||
}
|
||||
|
||||
return rootNode, nil
|
||||
}
|
||||
|
||||
type fileToTar struct {
|
||||
sourcePath string
|
||||
targetFileName string
|
||||
}
|
||||
|
||||
func newDirNode() *dirNode {
|
||||
return &dirNode{
|
||||
children: make(map[string]*dirNode),
|
||||
}
|
||||
}
|
||||
|
||||
type dirNode struct {
|
||||
children map[string]*dirNode
|
||||
files []fileToTar
|
||||
}
|
||||
|
||||
func (n *dirNode) addDir(dirPath string) {
|
||||
current := n
|
||||
for _, segment := range strings.Split(dirPath, "/") {
|
||||
if child, ok := n.children[segment]; ok {
|
||||
current = child
|
||||
} else {
|
||||
newNode := newDirNode()
|
||||
current.children[segment] = newNode
|
||||
current = newNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *dirNode) addFile(sourcePath, targetPath string) {
|
||||
dirPath, fileName := filepath.Split(targetPath)
|
||||
current := n
|
||||
for _, segment := range strings.Split(dirPath, "/") {
|
||||
if segment == "" {
|
||||
continue
|
||||
}
|
||||
if child, ok := current.children[segment]; ok {
|
||||
current = child
|
||||
} else {
|
||||
newNode := &dirNode{
|
||||
children: make(map[string]*dirNode),
|
||||
}
|
||||
current.children[segment] = newNode
|
||||
current = newNode
|
||||
}
|
||||
}
|
||||
|
||||
current.files = append(current.files, fileToTar{
|
||||
sourcePath: sourcePath,
|
||||
targetFileName: fileName,
|
||||
})
|
||||
}
|
||||
|
||||
func (n *dirNode) writeToTar(writer *tar.Writer, parent string) error {
|
||||
for segment, child := range n.children {
|
||||
segmentPath := filepath.Join(parent, segment)
|
||||
header := &tar.Header{
|
||||
Name: segmentPath,
|
||||
Typeflag: tar.TypeDir,
|
||||
// Use a fixed Mode, so that this isn't sensitive to the directory and umask
|
||||
// under which it was created. Additionally, windows can only set 0222,
|
||||
// 0444, or 0666, none of which are executable.
|
||||
Mode: 0555,
|
||||
ModTime: defaultCreationTime,
|
||||
}
|
||||
|
||||
if err := writer.WriteHeader(header); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := child.writeToTar(writer, segmentPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for i := range n.files {
|
||||
fileSpec := n.files[i]
|
||||
info, err := os.Stat(fileSpec.sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.Open(fileSpec.sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header := &tar.Header{
|
||||
Name: path.Join(parent, fileSpec.targetFileName),
|
||||
Size: info.Size(),
|
||||
Typeflag: tar.TypeReg,
|
||||
// Use a fixed Mode, so that this isn't sensitive to the directory and umask
|
||||
// under which it was created. Additionally, windows can only set 0222,
|
||||
// 0444, or 0666, none of which are executable.
|
||||
Mode: 0o555,
|
||||
ModTime: defaultCreationTime,
|
||||
}
|
||||
|
||||
if err = writer.WriteHeader(header); err != nil {
|
||||
return errors.Join(err, f.Close())
|
||||
}
|
||||
|
||||
if _, err = io.Copy(writer, f); err != nil {
|
||||
return errors.Join(err, f.Close())
|
||||
}
|
||||
|
||||
if err = f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
23
modules/packaging/registration.go
Normal file
23
modules/packaging/registration.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package packaging
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/gohcl"
|
||||
|
||||
"code.icb4dc0.de/buildr/buildr/internal/logging"
|
||||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
"code.icb4dc0.de/buildr/buildr/modules/packaging/ociimg"
|
||||
)
|
||||
|
||||
var Registration = modules.RegistrationFunc(func(registry *modules.TypeRegistry) {
|
||||
registry.RegisterModule(modules.ModuleTypePackage, "container_image", modules.ModuleFactoryFunc(func(block modules.Block, hclCtx *hcl.EvalContext) (modules.Module, error) {
|
||||
b := new(ociimg.ContainerImage)
|
||||
diags := gohcl.DecodeBody(block.Body(), hclCtx, b)
|
||||
if diags.HasErrors() {
|
||||
logging.Diagnostics(diags, nil)
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}))
|
||||
})
|
|
@ -12,10 +12,26 @@ func (f ModuleFactoryFunc) Create(block Block, hclCtx *hcl.EvalContext) (Module,
|
|||
return f(block, hclCtx)
|
||||
}
|
||||
|
||||
func NewRegistry() *TypeRegistry {
|
||||
return &TypeRegistry{
|
||||
type Registration interface {
|
||||
RegisterAt(registry *TypeRegistry)
|
||||
}
|
||||
|
||||
type RegistrationFunc func(registry *TypeRegistry)
|
||||
|
||||
func (f RegistrationFunc) RegisterAt(registry *TypeRegistry) {
|
||||
f(registry)
|
||||
}
|
||||
|
||||
func NewRegistry(registrations ...Registration) *TypeRegistry {
|
||||
r := &TypeRegistry{
|
||||
registrations: make(map[moduleSpec]ModuleFactory),
|
||||
}
|
||||
|
||||
for i := range registrations {
|
||||
registrations[i].RegisterAt(r)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
type TypeRegistry struct {
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
func RegisterTypes(registry *modules.TypeRegistry) {
|
||||
var Registration = modules.RegistrationFunc(func(registry *modules.TypeRegistry) {
|
||||
registry.RegisterModule("task", "script", modules.ModuleFactoryFunc(func(block modules.Block, hclCtx *hcl.EvalContext) (modules.Module, error) {
|
||||
b := new(ScriptTask)
|
||||
diags := gohcl.DecodeBody(block.Body(), hclCtx, b)
|
||||
|
@ -22,4 +22,4 @@ func RegisterTypes(registry *modules.TypeRegistry) {
|
|||
|
||||
return b, nil
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"code.icb4dc0.de/buildr/buildr/modules"
|
||||
)
|
||||
|
||||
func RegisterTypes(registry *modules.TypeRegistry) {
|
||||
var Registration = modules.RegistrationFunc(func(registry *modules.TypeRegistry) {
|
||||
registry.RegisterModule("tool", "go_tool", modules.ModuleFactoryFunc(func(block modules.Block, hclCtx *hcl.EvalContext) (modules.Module, error) {
|
||||
b := new(GoTool)
|
||||
diags := gohcl.DecodeBody(block.Body(), hclCtx, b)
|
||||
|
@ -19,4 +19,4 @@ func RegisterTypes(registry *modules.TypeRegistry) {
|
|||
|
||||
return b, nil
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
package modules
|
||||
|
||||
import "fmt"
|
||||
|
||||
type ModuleType string
|
||||
|
||||
func (t ModuleType) String() string {
|
||||
return string(t)
|
||||
}
|
||||
|
||||
func (t ModuleType) GroupName() string {
|
||||
return fmt.Sprintf("%ss", t)
|
||||
}
|
||||
|
||||
const (
|
||||
ModuleTypeTool ModuleType = "tool"
|
||||
ModuleTypeTask ModuleType = "task"
|
||||
ModuleTypeBuild ModuleType = "build"
|
||||
ModuleTypeTool ModuleType = "tool"
|
||||
ModuleTypeTask ModuleType = "task"
|
||||
ModuleTypeBuild ModuleType = "build"
|
||||
ModuleTypePackage ModuleType = "package"
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue