added basic plugin structure
This commit is contained in:
commit
a693cbad37
10
README.md
Normal file
10
README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Char
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# file: .char.yml
|
||||||
|
registry: git.front.kjuulh.io
|
||||||
|
plugins:
|
||||||
|
"kjuulh/char#/plugins/gocli":
|
||||||
|
vars:
|
||||||
|
name: "char"
|
||||||
|
```
|
40
cmd/char/ls.go
Normal file
40
cmd/char/ls.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package char
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.front.kjuulh.io/kjuulh/char/pkg/register"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewLsCommand() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "ls",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
r, err := register.
|
||||||
|
NewPluginRegisterBuilder().
|
||||||
|
Add("gocli", "").
|
||||||
|
Build(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
about, err := r.About(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for plugin, aboutText := range about {
|
||||||
|
fmt.Printf("plugin: %s\n", plugin)
|
||||||
|
fmt.Printf("\tabout: %s\n", aboutText)
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
15
cmd/char/root.go
Normal file
15
cmd/char/root.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package char
|
||||||
|
|
||||||
|
import "github.com/spf13/cobra"
|
||||||
|
|
||||||
|
func NewCharCmd() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "char",
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.AddCommand(
|
||||||
|
NewLsCommand(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
1
examples/basic/.char/plugins/gocli
Symbolic link
1
examples/basic/.char/plugins/gocli
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../
|
3
examples/basic/test.sh
Executable file
3
examples/basic/test.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
go run ../../main.go ls
|
27
go.mod
Normal file
27
go.mod
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
module git.front.kjuulh.io/kjuulh/char
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/hashicorp/go-hclog v0.14.1
|
||||||
|
github.com/hashicorp/go-plugin v1.4.5
|
||||||
|
github.com/spf13/cobra v1.6.1
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/fatih/color v1.7.0 // indirect
|
||||||
|
github.com/golang/protobuf v1.3.4 // indirect
|
||||||
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.10 // indirect
|
||||||
|
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect
|
||||||
|
github.com/oklog/run v1.0.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be // indirect
|
||||||
|
golang.org/x/text v0.3.0 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect
|
||||||
|
google.golang.org/grpc v1.27.1 // indirect
|
||||||
|
)
|
87
go.sum
Normal file
87
go.sum
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
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/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
|
||||||
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU=
|
||||||
|
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
|
github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo=
|
||||||
|
github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
|
||||||
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
||||||
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
||||||
|
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||||
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||||
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
|
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
|
||||||
|
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
||||||
|
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||||
|
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_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||||
|
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
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-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
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=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
||||||
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
1
go.work.sum
Normal file
1
go.work.sum
Normal file
@ -0,0 +1 @@
|
|||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
13
main.go
Normal file
13
main.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"git.front.kjuulh.io/kjuulh/char/cmd/char"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := char.NewCharCmd().Execute(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
1
pkg/plugins/script/script.go
Normal file
1
pkg/plugins/script/script.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package script
|
5
pkg/register/plugin.go
Normal file
5
pkg/register/plugin.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package register
|
||||||
|
|
||||||
|
type Plugin interface {
|
||||||
|
About() string
|
||||||
|
}
|
19
pkg/register/plugin_api.go
Normal file
19
pkg/register/plugin_api.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package register
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/rpc"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginAPI struct {
|
||||||
|
Impl Plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PluginAPI) Server(*plugin.MuxBroker) (any, error) {
|
||||||
|
return &PluginServer{Impl: pa.Impl}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*PluginAPI) Client(b *plugin.MuxBroker, c *rpc.Client) (any, error) {
|
||||||
|
return &PluginClient{client: c}, nil
|
||||||
|
}
|
48
pkg/register/plugin_builder.go
Normal file
48
pkg/register/plugin_builder.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package register
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-hclog"
|
||||||
|
"github.com/hashicorp/go-plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginBuilder struct {
|
||||||
|
serveConfig *plugin.ServeConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPluginBuilder(name string, p Plugin) *PluginBuilder {
|
||||||
|
logger := hclog.New(&hclog.LoggerOptions{
|
||||||
|
Level: hclog.Trace,
|
||||||
|
Output: os.Stderr,
|
||||||
|
JSONFormat: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
var pluginMap = map[string]plugin.Plugin{
|
||||||
|
name: &PluginAPI{
|
||||||
|
Impl: p,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
serveConfig := &plugin.ServeConfig{
|
||||||
|
HandshakeConfig: plugin.HandshakeConfig{
|
||||||
|
ProtocolVersion: 1,
|
||||||
|
MagicCookieKey: "BASIC_PLUGIN",
|
||||||
|
MagicCookieValue: "char",
|
||||||
|
},
|
||||||
|
Plugins: pluginMap,
|
||||||
|
Logger: logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PluginBuilder{
|
||||||
|
serveConfig: serveConfig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *PluginBuilder) Serve(ctx context.Context) error {
|
||||||
|
plugin.Serve(
|
||||||
|
pr.serveConfig,
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
22
pkg/register/plugin_client.go
Normal file
22
pkg/register/plugin_client.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package register
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginClient struct {
|
||||||
|
client *rpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Plugin = &PluginClient{}
|
||||||
|
|
||||||
|
func (pc *PluginClient) About() string {
|
||||||
|
var resp string
|
||||||
|
err := pc.client.Call("Plugin.About", new(any), &resp)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
147
pkg/register/plugin_register.go
Normal file
147
pkg/register/plugin_register.go
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package register
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-hclog"
|
||||||
|
"github.com/hashicorp/go-plugin"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginRegisterBuilder struct {
|
||||||
|
plugins map[string]PluginAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPluginRegisterBuilder() *PluginRegisterBuilder {
|
||||||
|
return &PluginRegisterBuilder{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *PluginRegisterBuilder) Add(name, path string) *PluginRegisterBuilder {
|
||||||
|
pr.plugins[name] = PluginAPI{}
|
||||||
|
|
||||||
|
return pr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *PluginRegisterBuilder) Build(ctx context.Context) (*PluginRegister, error) {
|
||||||
|
clients := make(map[string]*pluginClientWrapper, 0)
|
||||||
|
errgroup, _ := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
|
for name, p := range pr.plugins {
|
||||||
|
name, p := name, p
|
||||||
|
|
||||||
|
errgroup.Go(func() error {
|
||||||
|
client := plugin.NewClient(&plugin.ClientConfig{
|
||||||
|
HandshakeConfig: plugin.HandshakeConfig{
|
||||||
|
ProtocolVersion: 1,
|
||||||
|
MagicCookieKey: "BASIC_PLUGIN",
|
||||||
|
MagicCookieValue: "char",
|
||||||
|
},
|
||||||
|
Logger: hclog.New(&hclog.LoggerOptions{
|
||||||
|
Name: "char",
|
||||||
|
Output: os.Stdout,
|
||||||
|
Level: hclog.Debug,
|
||||||
|
}),
|
||||||
|
Cmd: exec.Command("sh", "-c", fmt.Sprintf(
|
||||||
|
"(cd ./.char/plugins/%s; go run plugins/%s/main.go)",
|
||||||
|
name,
|
||||||
|
name,
|
||||||
|
)),
|
||||||
|
Plugins: map[string]plugin.Plugin{
|
||||||
|
name: &p,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
rpcClient, err := client.Client()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := rpcClient.Dispense(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginApi, ok := raw.(Plugin)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("could not cast as plugin")
|
||||||
|
}
|
||||||
|
|
||||||
|
clients[name] = &pluginClientWrapper{
|
||||||
|
plugin: pluginApi,
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err := errgroup.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PluginRegister{
|
||||||
|
clients: clients,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
type pluginClientWrapper struct {
|
||||||
|
plugin Plugin
|
||||||
|
client *plugin.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pcw *pluginClientWrapper) Close() {
|
||||||
|
pcw.client.Kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
type PluginRegister struct {
|
||||||
|
clients map[string]*pluginClientWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *PluginRegister) Close() error {
|
||||||
|
errgroup, _ := errgroup.WithContext(context.Background())
|
||||||
|
|
||||||
|
for _, c := range pr.clients {
|
||||||
|
c := c
|
||||||
|
|
||||||
|
errgroup.Go(func() error {
|
||||||
|
c.Close()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := errgroup.Wait(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *PluginRegister) About(ctx context.Context) (map[string]string, error) {
|
||||||
|
list := make(map[string]string, len(pr.clients))
|
||||||
|
|
||||||
|
errgroup, ctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
|
for n, c := range pr.clients {
|
||||||
|
n, c := n, c
|
||||||
|
errgroup.Go(func() error {
|
||||||
|
about := c.plugin.About()
|
||||||
|
|
||||||
|
list[n] = about
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := errgroup.Wait(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, nil
|
||||||
|
}
|
10
pkg/register/plugin_server.go
Normal file
10
pkg/register/plugin_server.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package register
|
||||||
|
|
||||||
|
type PluginServer struct {
|
||||||
|
Impl Plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ps *PluginServer) About(args any, resp *string) error {
|
||||||
|
*resp = ps.Impl.About()
|
||||||
|
return nil
|
||||||
|
}
|
29
plugins/gocli/main.go
Normal file
29
plugins/gocli/main.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"git.front.kjuulh.io/kjuulh/char/pkg/register"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GoCliPlugin struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// About implements register.Plugin
|
||||||
|
func (*GoCliPlugin) About() string {
|
||||||
|
return "gocli"
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ register.Plugin = &GoCliPlugin{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := register.
|
||||||
|
NewPluginBuilder(
|
||||||
|
"gocli",
|
||||||
|
&GoCliPlugin{},
|
||||||
|
).
|
||||||
|
Serve(context.Background()); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user