From ec887fc718c5eb73100228f9b79e1dba39129a01 Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Mon, 14 Oct 2024 16:17:49 +0200 Subject: [PATCH] Support standard object types for command plugins + options for templater types (#958) #### What this PR does / why we need it - Support standard object types for command plugins The CLI supports verbs on objects (e.g, get component). For such object names aliases are used (e.g. for componentversions, it is possible to use component or cv, instead) A CLI command provided by a plugin may use such a standard object name. The new integration takes the aliases provided by the CLI into account. - Options for templater types Templaters are used by the CLI to process the constructor files, but possible also by direct lib users. So far, templaters are created for a value set, but without other arbitrary type specific optional parameters. The templater configuration now offers settings passed to the templater constructor. This is used by spiff to enable or restrict the OS mode. By default, file system access is enabled,. OS access is enabled if no virtual filesystem is used. With this configuration option, the user of the templater may configure tis behaviour. #### Which issue(s) this PR fixes --- api/cli/internal/context.go | 7 ++++++ api/utils/template/gotmpl.go | 2 +- api/utils/template/none.go | 2 +- api/utils/template/registry.go | 19 ++++++++++++---- api/utils/template/spiff.go | 13 +++++++++-- api/utils/template/subst.go | 2 +- api/utils/template/template.go | 3 ++- cmds/ocm/app/app.go | 9 +++++++- cmds/ocm/commands/ocmcmds/names/names.go | 29 ++++++++++++++++++++++++ go.mod | 4 ++-- go.sum | 8 +++---- 11 files changed, 81 insertions(+), 17 deletions(-) diff --git a/api/cli/internal/context.go b/api/cli/internal/context.go index d5314bd32d..b871fd02b9 100644 --- a/api/cli/internal/context.go +++ b/api/cli/internal/context.go @@ -7,6 +7,7 @@ import ( "github.com/mandelsoft/goutils/errors" "github.com/mandelsoft/goutils/general" + "github.com/mandelsoft/vfs/pkg/osfs" "github.com/mandelsoft/vfs/pkg/vfs" "ocm.software/ocm/api/config" @@ -39,6 +40,12 @@ type FileSystem struct { vfs.FileSystem } +var _ osfs.OsFsCheck = (*FileSystem)(nil) + +func (f *FileSystem) IsOsFileSystem() bool { + return osfs.IsOsFileSystem(f.FileSystem) +} + func (f *FileSystem) ApplyOption(options accessio.Options) error { options.SetPathFileSystem(f.FileSystem) return nil diff --git a/api/utils/template/gotmpl.go b/api/utils/template/gotmpl.go index e6c0acd11c..542d90311e 100644 --- a/api/utils/template/gotmpl.go +++ b/api/utils/template/gotmpl.go @@ -8,7 +8,7 @@ import ( ) func init() { - Register("go", func(_ vfs.FileSystem) Templater { return NewGo() }, `go templating supports complex values. + Register("go", func(_ vfs.FileSystem, _ TemplaterOptions) Templater { return NewGo() }, `go templating supports complex values.
   key:
     subkey: "abc {{.MY_VAL}}"
diff --git a/api/utils/template/none.go b/api/utils/template/none.go
index aeb321d2b8..bb0856ba0a 100644
--- a/api/utils/template/none.go
+++ b/api/utils/template/none.go
@@ -5,7 +5,7 @@ import (
 )
 
 func init() {
-	Register("none", func(_ vfs.FileSystem) Templater { return NewSubst() }, `do not do any substitution.
+	Register("none", func(_ vfs.FileSystem, _ TemplaterOptions) Templater { return NewSubst() }, `do not do any substitution.
 `)
 }
 
diff --git a/api/utils/template/registry.go b/api/utils/template/registry.go
index 44cee97318..db14434f1f 100644
--- a/api/utils/template/registry.go
+++ b/api/utils/template/registry.go
@@ -6,6 +6,7 @@ import (
 	"sync"
 
 	"github.com/mandelsoft/goutils/errors"
+	"github.com/mandelsoft/goutils/general"
 	"github.com/mandelsoft/vfs/pkg/vfs"
 
 	"ocm.software/ocm/api/utils"
@@ -13,11 +14,21 @@ import (
 
 const KIND_TEMPLATER = "templater"
 
-type TemplaterFactory func(system vfs.FileSystem) Templater
+type (
+	TemplaterOptions map[string]interface{}
+	TemplaterFactory func(system vfs.FileSystem, options TemplaterOptions) Templater
+)
+
+func (t TemplaterOptions) Get(name string) interface{} {
+	if t == nil {
+		return nil
+	}
+	return t[name]
+}
 
 type Registry interface {
 	Register(name string, fac TemplaterFactory, desc string)
-	Create(name string, fs vfs.FileSystem) (Templater, error)
+	Create(name string, fs vfs.FileSystem, options ...TemplaterOptions) (Templater, error)
 	Describe(name string) (string, error)
 	KnownTypeNames() []string
 }
@@ -48,7 +59,7 @@ func (r *registry) Register(name string, fac TemplaterFactory, desc string) {
 	}
 }
 
-func (r *registry) Create(name string, fs vfs.FileSystem) (Templater, error) {
+func (r *registry) Create(name string, fs vfs.FileSystem, options ...TemplaterOptions) (Templater, error) {
 	r.lock.RLock()
 	defer r.lock.RUnlock()
 
@@ -56,7 +67,7 @@ func (r *registry) Create(name string, fs vfs.FileSystem) (Templater, error) {
 	if !ok {
 		return nil, errors.ErrNotSupported(KIND_TEMPLATER, name)
 	}
-	return t.templater(fs), nil
+	return t.templater(fs, general.Optional(options...)), nil
 }
 
 func (r *registry) Describe(name string) (string, error) {
diff --git a/api/utils/template/spiff.go b/api/utils/template/spiff.go
index 5d303f2bfe..8088ed2f07 100644
--- a/api/utils/template/spiff.go
+++ b/api/utils/template/spiff.go
@@ -9,6 +9,8 @@ import (
 	"github.com/mandelsoft/vfs/pkg/vfs"
 )
 
+const SPIFF_MODE = "mode"
+
 func init() {
 	Register("spiff", NewSpiff, `[spiff templating](https://github.com/mandelsoft/spiff).
 It supports complex values. the settings are accessible using the binding values.
@@ -23,9 +25,16 @@ type Spiff struct {
 	spiff spiffing.Spiff
 }
 
-func NewSpiff(fs vfs.FileSystem) Templater {
+func NewSpiff(fs vfs.FileSystem, opts TemplaterOptions) Templater {
+	s := spiffing.New().WithFileSystem(fs).WithFeatures(features.CONTROL, features.INTERPOLATION)
+
+	m := opts.Get(SPIFF_MODE)
+
+	if mode, ok := m.(int); ok {
+		s = s.WithMode(mode)
+	}
 	return &Spiff{
-		spiffing.New().WithFileSystem(fs).WithFeatures(features.CONTROL, features.INTERPOLATION),
+		s,
 	}
 }
 
diff --git a/api/utils/template/subst.go b/api/utils/template/subst.go
index e8778e0fe4..e504aa87c3 100644
--- a/api/utils/template/subst.go
+++ b/api/utils/template/subst.go
@@ -10,7 +10,7 @@ import (
 )
 
 func init() {
-	Register("subst", func(_ vfs.FileSystem) Templater { return NewSubst() }, `simple value substitution with the drone/envsubst templater.
+	Register("subst", func(_ vfs.FileSystem, _ TemplaterOptions) Templater { return NewSubst() }, `simple value substitution with the drone/envsubst templater.
 It supports string values, only. Complex settings will be json encoded.
 
   key:
diff --git a/api/utils/template/template.go b/api/utils/template/template.go
index 84935bd963..a1223c0cf1 100644
--- a/api/utils/template/template.go
+++ b/api/utils/template/template.go
@@ -30,6 +30,7 @@ type Options struct {
 	UseEnv    bool
 	Templater Templater
 	Vars      Values
+	Options   map[string]interface{}
 }
 
 func (o *Options) DefaultMode() string {
@@ -63,7 +64,7 @@ func (o *Options) Complete(fs vfs.FileSystem) error {
 			}
 		}
 	}
-	o.Templater, err = DefaultRegistry().Create(o.Mode, fs)
+	o.Templater, err = DefaultRegistry().Create(o.Mode, fs, o.Options)
 	if err != nil {
 		return err
 	}
diff --git a/cmds/ocm/app/app.go b/cmds/ocm/app/app.go
index 300e64b52a..d0266a7f4d 100644
--- a/cmds/ocm/app/app.go
+++ b/cmds/ocm/app/app.go
@@ -32,6 +32,7 @@ import (
 	"ocm.software/ocm/cmds/ocm/commands/ocmcmds"
 	"ocm.software/ocm/cmds/ocm/commands/ocmcmds/componentarchive"
 	"ocm.software/ocm/cmds/ocm/commands/ocmcmds/components"
+	"ocm.software/ocm/cmds/ocm/commands/ocmcmds/names"
 	"ocm.software/ocm/cmds/ocm/commands/ocmcmds/plugins"
 	"ocm.software/ocm/cmds/ocm/commands/ocmcmds/pubsub"
 	"ocm.software/ocm/cmds/ocm/commands/ocmcmds/references"
@@ -309,11 +310,17 @@ func newCliCommand(opts *CLIOptions, mod ...func(clictx.Context, *cobra.Command)
 					v = verbs.NewCommand(ctx, c.Verb, "additional plugin based commands")
 					cmd.AddCommand(v)
 				}
+				types := []string{objtype}
+				if len(names.Aliases[objtype]) != 0 {
+					types = names.Aliases[objtype]
+				}
+
 				s := cobrautils.Find(v, objtype)
 				if s != nil {
 					out.Errf(opts.Context, "duplicate cli command %q of plugin %q for verb %q", objtype, p.Name(), c.Verb)
 				} else {
-					v.AddCommand(plugin.NewCommand(ctx, p, c.Name, objtype))
+					cmd := plugin.NewCommand(ctx, p, c.Name, types...)
+					v.AddCommand(cmd)
 				}
 
 				if c.Realm != "" {
diff --git a/cmds/ocm/commands/ocmcmds/names/names.go b/cmds/ocm/commands/ocmcmds/names/names.go
index 24927051fd..652c1c46cf 100644
--- a/cmds/ocm/commands/ocmcmds/names/names.go
+++ b/cmds/ocm/commands/ocmcmds/names/names.go
@@ -18,3 +18,32 @@ var (
 	PubSub                 = []string{"pubsub", "ps"}
 	Verified               = []string{"verified"}
 )
+
+var Aliases = map[string][]string{}
+
+func init() {
+	add(
+		ComponentArchive,
+		CommonTransportArchive,
+		Components,
+		CLI,
+		Configuration,
+		ResourceConfig,
+		SourceConfig,
+		Resources,
+		Sources,
+		References,
+		Versions,
+		Plugins,
+		Action,
+		RoutingSlips,
+		PubSub,
+		Verified,
+	)
+}
+
+func add(aliases ...[]string) {
+	for _, a := range aliases {
+		Aliases[a[0]] = a
+	}
+}
diff --git a/go.mod b/go.mod
index 70c7c3ac16..ad142a2408 100644
--- a/go.mod
+++ b/go.mod
@@ -44,8 +44,8 @@ require (
 	github.com/mandelsoft/filepath v0.0.0-20240223090642-3e2777258aa3
 	github.com/mandelsoft/goutils v0.0.0-20240915132328-95975bffaef0
 	github.com/mandelsoft/logging v0.0.0-20240618075559-fdca28a87b0a
-	github.com/mandelsoft/spiff v1.7.0-beta-5
-	github.com/mandelsoft/vfs v0.4.4-0.20240915223828-8bc9369139c8
+	github.com/mandelsoft/spiff v1.3.0-beta-7.0.20241014123229-b7af70637d7b
+	github.com/mandelsoft/vfs v0.4.4
 	github.com/marstr/guid v1.1.0
 	github.com/mikefarah/yq/v4 v4.44.3
 	github.com/mitchellh/copystructure v1.2.0
diff --git a/go.sum b/go.sum
index d6f7705744..eb86b4f65d 100644
--- a/go.sum
+++ b/go.sum
@@ -694,10 +694,10 @@ github.com/mandelsoft/goutils v0.0.0-20240915132328-95975bffaef0 h1:MtIgCrVzBP5t
 github.com/mandelsoft/goutils v0.0.0-20240915132328-95975bffaef0/go.mod h1:9TJgkwSY43RWHiIAAz7fL8SEIHf0L13Pk4w8fDIt+i4=
 github.com/mandelsoft/logging v0.0.0-20240618075559-fdca28a87b0a h1:MAvh0gbP2uwKmf7wWCkYCzrYa6vPjBvYeGhoUlVHwtI=
 github.com/mandelsoft/logging v0.0.0-20240618075559-fdca28a87b0a/go.mod h1:uO460C1lIB3IOOgrbXhAlz3AKsOv4T2K6ALBn3PwuSg=
-github.com/mandelsoft/spiff v1.7.0-beta-5 h1:3kC10nTviDQhL8diSxp7i4IC2iSiDg6KPbH1CAq7Lfw=
-github.com/mandelsoft/spiff v1.7.0-beta-5/go.mod h1:TwEeOPuRZxlzQBCLEyVTlHmBSruSGGNdiQ2fovVJ8ao=
-github.com/mandelsoft/vfs v0.4.4-0.20240915223828-8bc9369139c8 h1:tMAYF0nqqsoiUb6SZ+CneodHYTqQ0jLjL0PqOmKGBbo=
-github.com/mandelsoft/vfs v0.4.4-0.20240915223828-8bc9369139c8/go.mod h1:zmbhx2ueQc96buqNXg2S88McBMm2mNFNeyGSpSebrHw=
+github.com/mandelsoft/spiff v1.3.0-beta-7.0.20241014123229-b7af70637d7b h1:SyTUzkWcjNOZ1O1iULcTo65DzQbP8KDbKMre1aw/hKs=
+github.com/mandelsoft/spiff v1.3.0-beta-7.0.20241014123229-b7af70637d7b/go.mod h1:HXurS33cKPLXXAI3SYll+Z6QotB1yzFFDyOFZ4QODcA=
+github.com/mandelsoft/vfs v0.4.4 h1:hq+nI7NWzLLWR3Ii/w4agup4KpWjLpw6dAGtmvWr1Vw=
+github.com/mandelsoft/vfs v0.4.4/go.mod h1:3ODt1ze/dCdOJCbhHX8ARAw7l422fDZUhbt0wqplBRs=
 github.com/marstr/guid v1.1.0 h1:/M4H/1G4avsieL6BbUwCOBzulmoeKVP5ux/3mQNnbyI=
 github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=