Skip to content

Commit

Permalink
More lazy init
Browse files Browse the repository at this point in the history
  • Loading branch information
dsimansk committed Oct 20, 2023
1 parent c0c511c commit 7e5bef5
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 66 deletions.
23 changes: 12 additions & 11 deletions cmd/kn/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ func run(args []string) error {
}

// FT: Context Sharing
var ctxManager *pluginpkg.ContextDataManager
if config.GlobalConfig.ContextSharing() {
ctxManager, err := pluginpkg.NewContextManager()
ctxManager, err = pluginpkg.NewContextManager(pluginManager)
if err != nil {
return err
}
Expand All @@ -96,15 +97,6 @@ func run(args []string) error {
println("error during write")
}
}(ctxManager)

err = ctxManager.FetchManifests(pluginManager)
if err != nil {
return err
}

// Inject shared context data as context.Context
contextData := ctxManager.FetchContextData(pluginManager)
rootCmd.SetContext(contextData)
}

if plugin != nil {
Expand All @@ -113,7 +105,16 @@ func run(args []string) error {
if err != nil {
return err
}

if config.GlobalConfig.ContextSharing() {
if pwm, ok := plugin.(pluginpkg.PluginWithManifest); ok {
data, _ := ctxManager.FetchContextData()
err := pwm.ExecuteWithContext(data, argsWithoutCommands(args, plugin.CommandParts()))
if err != nil {
return &runError{err: err}
}
}
return nil
}
err := plugin.Execute(argsWithoutCommands(args, plugin.CommandParts()))
if err != nil {
return &runError{err: err}
Expand Down
10 changes: 7 additions & 3 deletions pkg/kn/commands/service/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"errors"
"fmt"
"io"

"knative.dev/client/pkg/kn/plugin"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -102,8 +102,12 @@ func NewServiceDescribeCommand(p *commands.KnParams) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
var serviceName string
if len(args) != 1 {
if cmd.Context() != nil && cmd.Context().Value("service") != nil {
serviceName = cmd.Context().Value("service").(string)
if plugin.CtxManager != nil {
data, err := plugin.CtxManager.FetchContextData()
if err != nil {
return err
}
serviceName = data["service"]
}
if serviceName == "" {
return errors.New("'service describe' requires the service name given as single argument")
Expand Down
99 changes: 53 additions & 46 deletions pkg/kn/plugin/context_sharing.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package plugin

import (
"bytes"
"context"
"encoding/json"
"io/fs"
"os"
Expand All @@ -28,10 +27,6 @@ import (
)

//--TYPES--
//TODO: move types into its own file

//TODO: let's see if we need this map
//type ContextData map[string]string

// Manifest represents plugin metadata
type Manifest struct {
Expand All @@ -44,7 +39,6 @@ type Manifest struct {
// ProducesContextDataKeys is a list of keys for the ContextData that
// a plugin can produce. Nil or an empty list declares that this
// plugin is not ContextDataProducer
//TODO: well-known keys could be const, or this can be its own data structure
ProducesContextDataKeys []string `json:"producesKeys,omitempty"`

// ConsumesContextDataKeys is a list of keys from a ContextData that a
Expand All @@ -65,7 +59,7 @@ type PluginWithManifest interface {
GetContextData() map[string]string

// ExecuteWithContext
ExecuteWithContext(ctx context.Context, args []string) error
ExecuteWithContext(ctx map[string]string, args []string) error
}

//--TYPES--
Expand All @@ -74,32 +68,19 @@ var CtxManager *ContextDataManager

type ContextDataManager struct {
//ContextData map[string]ContextData `json:"-"`
Producers map[string][]string `json:"producers"`
Consumers map[string][]string `json:"consumers"`
Manifests map[string]Manifest `json:"manifests"`
PluginManager *Manager `json:"-"`
Producers map[string][]string `json:"producers"`
Consumers map[string][]string `json:"consumers"`
Manifests map[string]Manifest `json:"manifests"`
}

func NewContextManager() (*ContextDataManager, error) {
func NewContextManager(pluginManager *Manager) (*ContextDataManager, error) {
if CtxManager == nil {
//println("opening file...")
//file, err := os.Open(filepath.Join(filepath.Dir(config.GlobalConfig.ConfigFile()), "context.json"))
//if err != nil {
// return nil, err
//}
//decoder := json.NewDecoder(file)
//ctxManager = &ContextDataManager{}
//if err := decoder.Decode(ctxManager); err != nil {
// return nil, err
//}
//out := new(bytes.Buffer)
//enc := json.NewEncoder(out)
//enc.SetIndent("", " ")
//enc.Encode(ctxManager)
//println(out.String())
CtxManager = &ContextDataManager{
Producers: map[string][]string{},
Consumers: map[string][]string{},
Manifests: map[string]Manifest{},
PluginManager: pluginManager,
Producers: map[string][]string{},
Consumers: map[string][]string{},
Manifests: map[string]Manifest{},
}
}
return CtxManager, nil
Expand All @@ -115,27 +96,31 @@ func (c *ContextDataManager) GetProducesKeys(pluginName string) []string {
return c.Manifests[pluginName].ProducesContextDataKeys
}

func (c *ContextDataManager) FetchContextData(pluginManager *Manager) context.Context {
ctx := context.Background()
for _, p := range pluginManager.GetInternalPlugins() {
func (c *ContextDataManager) FetchContextData() (map[string]string, error) {
// Load cached data first
if err := c.loadCache(); err != nil {
return nil, err
}

// Fetch manifests
if err := c.FetchManifests(); err != nil {
return nil, err
}

// Get context data, limited to func only
for _, p := range c.PluginManager.GetInternalPlugins() {
if p.Name() == "kn func" {
if pwm, ok := p.(PluginWithManifest); ok {
data := pwm.GetContextData()

for k, v := range data {
ctx = context.WithValue(ctx, k, v)
}
return pwm.GetContextData(), nil
}
}
}
//ctx = context.WithValue(ctx, "service", "hello")
return ctx

return map[string]string{}, nil
}

// FetchManifests it tries to retrieve manifest from both inlined and external plugins
func (c *ContextDataManager) FetchManifests(pluginManager *Manager) error {
for _, plugin := range pluginManager.GetInternalPlugins() {
func (c *ContextDataManager) FetchManifests() error {
for _, plugin := range c.PluginManager.GetInternalPlugins() {
manifest := &Manifest{}
// For the integrity build the same name format as external plugins
pluginName := "kn-" + strings.Join(plugin.CommandParts(), "-")
Expand All @@ -150,7 +135,7 @@ func (c *ContextDataManager) FetchManifests(pluginManager *Manager) error {
c.populateDataKeys(manifest, pluginName)
}
}
plugins, err := pluginManager.ListPlugins()
plugins, err := c.PluginManager.ListPlugins()
if err != nil {
return err
}
Expand Down Expand Up @@ -210,16 +195,38 @@ func fetchExternalManifest(p Plugin) *Manifest {
return manifest
}

// TODO: store to file actually
func (c *ContextDataManager) loadCache() error {
cacheFile := filepath.Join(filepath.Dir(config.GlobalConfig.ConfigFile()), "context.json")
if _, err := os.Stat(cacheFile); err != nil {
if os.IsNotExist(err) {
return nil // No cache file yet
} else {
return err
}
}

file, err := os.Open(cacheFile)
if err != nil {
return err
}
decoder := json.NewDecoder(file)
ctxManager := &ContextDataManager{}
if err := decoder.Decode(ctxManager); err != nil {
return err
}
c.Manifests = ctxManager.Manifests
c.Producers = ctxManager.Producers
c.Consumers = ctxManager.Consumers
return nil
}

// WriteCache store data back to cache file
func (c *ContextDataManager) WriteCache() error {
//println("\n====\nContext Data to be stored:")
out := new(bytes.Buffer)
enc := json.NewEncoder(out)
enc.SetIndent("", " ")
if err := enc.Encode(c); err != nil {
return nil
}
//println(out.String())
return os.WriteFile(filepath.Join(filepath.Dir(config.GlobalConfig.ConfigFile()), "context.json"), out.Bytes(), fs.FileMode(0664))
}
11 changes: 5 additions & 6 deletions pkg/kn/plugin/context_sharing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package plugin

import (
"context"
"os"
"path/filepath"
"strings"
Expand All @@ -34,7 +33,7 @@ type testPluginWithManifest struct {

func (t testPluginWithManifest) GetManifest() *Manifest { return t.manifest }
func (t testPluginWithManifest) GetContextData() map[string]string { return t.contextData }
func (t testPluginWithManifest) ExecuteWithContext(ctx context.Context, args []string) error {
func (t testPluginWithManifest) ExecuteWithContext(ctx map[string]string, args []string) error {
return nil
}

Expand Down Expand Up @@ -86,10 +85,10 @@ func TestFetchManifest(t *testing.T) {
})

if len(tc.cmdPart) == 0 {
ctxManager, err := NewContextManager()
ctxManager, err := NewContextManager(c.pluginManager)
assert.NilError(t, err)

err = ctxManager.FetchManifests(c.pluginManager)
err = ctxManager.FetchManifests()
assert.NilError(t, err)
assert.Assert(t, len(ctxManager.Manifests) == 0)
return
Expand All @@ -105,10 +104,10 @@ func TestFetchManifest(t *testing.T) {
prepareInternalPlugins(testPlugin{parts: tc.cmdPart})
}

ctxManager, err := NewContextManager()
ctxManager, err := NewContextManager(c.pluginManager)
assert.NilError(t, err)

err = ctxManager.FetchManifests(c.pluginManager)
err = ctxManager.FetchManifests()
assert.NilError(t, err)
assert.Assert(t, len(ctxManager.Manifests) == 1)

Expand Down

0 comments on commit 7e5bef5

Please sign in to comment.