with about plugins

This commit is contained in:
Kasper Juul Hermansen 2022-11-02 22:10:15 +01:00
parent e59a87c43a
commit c6fd666f64
Signed by: kjuulh
GPG Key ID: 0F95C140730F2F23
13 changed files with 250 additions and 46 deletions

13
cmd/char/limitedroot.go Normal file
View File

@ -0,0 +1,13 @@
package char
import (
"github.com/spf13/cobra"
)
func NewLimitedCharCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "char",
}
return cmd
}

View File

@ -3,48 +3,18 @@ package char
import ( import (
"fmt" "fmt"
"git.front.kjuulh.io/kjuulh/char/pkg/plugins/provider" "git.front.kjuulh.io/kjuulh/char/pkg/charcontext"
"git.front.kjuulh.io/kjuulh/char/pkg/register"
"git.front.kjuulh.io/kjuulh/char/pkg/schema"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func NewLsCommand() *cobra.Command { func NewLsCommand(charctx *charcontext.CharContext) *cobra.Command {
gpp := provider.NewGitPluginProvider()
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "ls", Use: "ls",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context() ctx := cmd.Context()
s, err := schema.ParseFile(ctx, ".char.yml") about, err := charctx.About(ctx)
if err != nil {
return err
}
plugins, err := s.GetPlugins(ctx)
if err != nil {
return err
}
err = gpp.FetchPlugins(ctx, s.Registry, plugins)
if err != nil {
return err
}
builder := register.NewPluginRegisterBuilder()
for name, plugin := range plugins {
builder = builder.Add(name.Hash(), plugin.Opts.Path)
}
r, err := builder.Build(ctx)
if err != nil {
return err
}
defer r.Close()
about, err := r.About(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -53,6 +23,36 @@ func NewLsCommand() *cobra.Command {
fmt.Printf("plugin: %s\n", a.Name) fmt.Printf("plugin: %s\n", a.Name)
fmt.Printf("\tversion: %s\n", a.Version) fmt.Printf("\tversion: %s\n", a.Version)
fmt.Printf("\tabout: %s\n", a.About) fmt.Printf("\tabout: %s\n", a.About)
if len(a.Vars) > 0 {
fmt.Println("\tVars:")
for _, av := range a.Vars {
fmt.Printf("\t\t%s\n", av)
}
}
if len(a.Commands) > 0 {
fmt.Println("\tCommands:")
for _, ac := range a.Commands {
fmt.Printf("\t\t%s", ac)
if len(ac.Args) == 0 {
continue
}
for _, aca := range ac.Args {
isrequired := false
for _, acr := range ac.Required {
if acr == aca {
isrequired = true
}
}
if isrequired {
fmt.Printf("\t\t\t%s: required\n", aca)
} else {
fmt.Printf("\t\t\t%s\n", aca)
}
}
}
}
fmt.Println()
} }
return nil return nil

View File

@ -1,14 +1,17 @@
package char package char
import "github.com/spf13/cobra" import (
"git.front.kjuulh.io/kjuulh/char/pkg/charcontext"
"github.com/spf13/cobra"
)
func NewCharCmd() *cobra.Command { func NewCharCmd(charctx *charcontext.CharContext) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "char", Use: "char",
} }
cmd.AddCommand( cmd.AddCommand(
NewLsCommand(), NewLsCommand(charctx),
) )
return cmd return cmd

View File

@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
set -e
go build -o char ../../main.go go build -o char ../../main.go
function devcharls() { function devcharls() {

Binary file not shown.

View File

@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
set -e
go build -o char ../../main.go go build -o char ../../main.go
CHAR_DEV_MODE=true ./char ls CHAR_DEV_MODE=true ./char ls

18
main.go
View File

@ -1,13 +1,29 @@
package main package main
import ( import (
"context"
"errors"
"log" "log"
"git.front.kjuulh.io/kjuulh/char/cmd/char" "git.front.kjuulh.io/kjuulh/char/cmd/char"
"git.front.kjuulh.io/kjuulh/char/pkg/charcontext"
) )
func main() { func main() {
if err := char.NewCharCmd().Execute(); err != nil { charctx, err := charcontext.NewCharContext(context.Background())
if err != nil {
if errors.Is(err, charcontext.ErrNoContextFound) {
log.Print("you are not in a char context, as such you will be presented with limited options")
if err := char.NewLimitedCharCmd().Execute(); err != nil {
log.Fatal(err)
}
} else {
log.Fatal(err)
}
}
defer charctx.Close()
if err := char.NewCharCmd(charctx).Execute(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }

View File

@ -0,0 +1,66 @@
package charcontext
import (
"context"
"log"
"git.front.kjuulh.io/kjuulh/char/pkg/plugins/provider"
"git.front.kjuulh.io/kjuulh/char/pkg/register"
"git.front.kjuulh.io/kjuulh/char/pkg/schema"
)
type CharContext struct {
contextPath string
pluginRegister *register.PluginRegister
schema *schema.CharSchema
}
func NewCharContext(ctx context.Context) (*CharContext, error) {
localPath, err := FindLocalRoot(ctx)
if err != nil {
return nil, err
}
gpp := provider.NewGitPluginProvider()
s, err := schema.ParseFile(ctx, ".char.yml")
if err != nil {
return nil, err
}
plugins, err := s.GetPlugins(ctx)
if err != nil {
return nil, err
}
err = gpp.FetchPlugins(ctx, s.Registry, plugins)
if err != nil {
return nil, err
}
builder := register.NewPluginRegisterBuilder()
for name, plugin := range plugins {
builder = builder.Add(name.Hash(), plugin.Opts.Path)
}
r, err := builder.Build(ctx)
if err != nil {
return nil, err
}
return &CharContext{
contextPath: localPath,
pluginRegister: r,
schema: s,
}, nil
}
func (cc *CharContext) Close() {
if err := cc.pluginRegister.Close(); err != nil {
log.Fatal(err)
}
}
func (cc *CharContext) About(ctx context.Context) ([]register.AboutItem, error) {
return cc.pluginRegister.About(ctx)
}

View File

@ -0,0 +1,57 @@
package charcontext
import (
"context"
"errors"
"os"
"path"
)
var ErrNoContextFound = errors.New("could not find project root")
const CharFileName = ".char.yml"
func FindLocalRoot(ctx context.Context) (string, error) {
curdir, err := os.Getwd()
if err != nil {
return "", err
}
return recursiveFindLocalRoot(ctx, curdir)
//output, err := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
//if err != nil {
// return "", err
//}
//if len(output) == 0 {
// return "", errors.New("could not find absolute path")
//}
//if _, err := os.Stat(string(output)); errors.Is(err, os.ErrNotExist) {
// return "", fmt.Errorf("path does not exist %s", string(output))
//}
//return string(output), nil
}
func recursiveFindLocalRoot(ctx context.Context, localpath string) (string, error) {
entries, err := os.ReadDir(localpath)
if err != nil {
return "", err
}
for _, entry := range entries {
if entry.Name() == CharFileName {
return localpath, nil
}
}
if localpath == "/" {
return "", ErrNoContextFound
}
return recursiveFindLocalRoot(ctx, path.Dir(localpath))
}
func ChangeToPath(_ context.Context, path string) error {
return os.Chdir(path)
}

View File

@ -2,10 +2,18 @@ package register
import "context" import "context"
type AboutCommand struct {
Name string `json:"name" yaml:"name"`
Args []string `json:"args" yaml:"args"`
Required []string `json:"required" yaml:"required"`
}
type About struct { type About struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version"` Version string `json:"version"`
About string `json:"about"` About string `json:"about"`
Vars []string `json:"vars"`
Commands []*AboutCommand `json:"commands"`
} }
type Plugin interface { type Plugin interface {

View File

@ -164,10 +164,32 @@ func (pr *PluginRegister) Close() error {
return nil return nil
} }
type CommandAboutItem struct {
Name string
Args []string
Required []string
}
type CommandAboutItems []*CommandAboutItem
func FromAboutCommands(commands []*AboutCommand) CommandAboutItems {
cai := make(CommandAboutItems, 0)
for _, command := range commands {
cai = append(cai, &CommandAboutItem{
Name: command.Name,
Args: command.Args,
Required: command.Required,
})
}
return cai
}
type AboutItem struct { type AboutItem struct {
Name string Name string
Version string Version string
About string About string
Vars []string
Commands CommandAboutItems
} }
func (pr *PluginRegister) About(ctx context.Context) ([]AboutItem, error) { func (pr *PluginRegister) About(ctx context.Context) ([]AboutItem, error) {
@ -184,9 +206,11 @@ func (pr *PluginRegister) About(ctx context.Context) ([]AboutItem, error) {
} }
list = append(list, AboutItem{ list = append(list, AboutItem{
Name: about.Name, Name: about.Name,
Version: about.Version, Version: about.Version,
About: about.About, About: about.About,
Vars: about.Vars,
Commands: FromAboutCommands(about.Commands),
}) })
return nil return nil
}) })

View File

@ -95,7 +95,10 @@ func (cspn CharSchemaPluginName) Get() (*PluginOps, error) {
} }
type CharSchemaPlugins map[CharSchemaPluginName]*CharSchemaPlugin type CharSchemaPlugins map[CharSchemaPluginName]*CharSchemaPlugin
type CharSchemaPluginVarName string
type CharSchemaPluginVars map[CharSchemaPluginVarName]string
type CharSchemaPlugin struct { type CharSchemaPlugin struct {
Opts *PluginOps Opts *PluginOps
Vars CharSchemaPluginVars `json:"vars"`
} }

View File

@ -14,6 +14,16 @@ func (*GoCliPlugin) About(ctx context.Context) (*register.About, error) {
Name: "gocli", Name: "gocli",
Version: "v0.0.1", Version: "v0.0.1",
About: "golang cli provides a set of actions and presets supporting golang development", About: "golang cli provides a set of actions and presets supporting golang development",
Vars: []string{
"dev.mode",
},
Commands: []*register.AboutCommand{
{
Name: "local_up",
Args: []string{"fish"},
Required: []string{"fish"},
},
},
}, nil }, nil
} }