From 5d664855ded60ce0dceefcd369645717bc5be247 Mon Sep 17 00:00:00 2001 From: James Shubin Date: Fri, 3 Mar 2023 14:12:09 -0500 Subject: [PATCH] lang: interfaces, funcs: Implement fmt.Stringer for functions This adds the requirement that all function implementations provider a String() string method so that these can be used as vertices in the pgraph library. If we eventually move to generics for the pgraph DAG, then this might not matter, but it's not bad that these have names either. --- lang/funcs/contains_polyfunc.go | 6 +++++ lang/funcs/core/datetime/now_fact.go | 14 ++++++++++- lang/funcs/core/deploy/abspath_func.go | 17 ++++++++++--- lang/funcs/core/deploy/readfile_func.go | 13 +++++++++- lang/funcs/core/deploy/readfileabs_func.go | 13 +++++++++- lang/funcs/core/example/flipflop_fact.go | 14 ++++++++++- lang/funcs/core/example/vumeter_func.go | 13 +++++++++- lang/funcs/core/fmt/printf_func.go | 19 ++++++++++---- lang/funcs/core/iter/map_func.go | 15 +++++++++-- lang/funcs/core/os/readfile_func.go | 13 +++++++++- lang/funcs/core/os/system_func.go | 13 +++++++++- lang/funcs/core/random1_func.go | 15 +++++++++-- lang/funcs/core/sys/cpucount_fact.go | 12 ++++++++- lang/funcs/core/sys/hostname_fact.go | 14 ++++++++++- lang/funcs/core/sys/load_fact.go | 12 ++++++++- lang/funcs/core/sys/uptime_fact.go | 14 ++++++++++- lang/funcs/core/template_func.go | 29 ++++++++++++++-------- lang/funcs/core/world/exchange_func.go | 13 +++++++++- lang/funcs/core/world/kvlookup_func.go | 13 +++++++++- lang/funcs/core/world/schedule_func.go | 11 +++++++- lang/funcs/facts/facts.go | 1 + lang/funcs/facts/func.go | 6 +++++ lang/funcs/history_polyfunc.go | 6 +++++ lang/funcs/maplookup_polyfunc.go | 6 +++++ lang/funcs/operator_polyfunc.go | 7 ++++++ lang/funcs/simple/simple.go | 10 +++++++- lang/funcs/simplepoly/simplepoly.go | 10 +++++++- lang/funcs/structlookup_polyfunc.go | 6 +++++ lang/funcs/structs/call.go | 11 ++++++++ lang/funcs/structs/composite.go | 11 ++++++++ lang/funcs/structs/const.go | 11 ++++++++ lang/funcs/structs/function.go | 11 ++++++++ lang/funcs/structs/if.go | 11 ++++++++ lang/funcs/structs/var.go | 11 ++++++++ lang/interfaces/func.go | 3 +++ 35 files changed, 365 insertions(+), 39 deletions(-) diff --git a/lang/funcs/contains_polyfunc.go b/lang/funcs/contains_polyfunc.go index 916ca657..3b9fe46c 100644 --- a/lang/funcs/contains_polyfunc.go +++ b/lang/funcs/contains_polyfunc.go @@ -48,6 +48,12 @@ type ContainsPolyFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *ContainsPolyFunc) String() string { + return ContainsFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *ContainsPolyFunc) ArgGen(index int) (string, error) { seq := []string{"needle", "haystack"} diff --git a/lang/funcs/core/datetime/now_fact.go b/lang/funcs/core/datetime/now_fact.go index 055b4cc4..be5bacc4 100644 --- a/lang/funcs/core/datetime/now_fact.go +++ b/lang/funcs/core/datetime/now_fact.go @@ -24,8 +24,14 @@ import ( "github.com/purpleidea/mgmt/lang/types" ) +const ( + // NowFuncName is the name this fact is registered as. It's still a Func + // Name because this is the name space the fact is actually using. + NowFuncName = "now" +) + func init() { - facts.ModuleRegister(ModuleName, "now", func() facts.Fact { return &DateTimeFact{} }) // must register the fact and name + facts.ModuleRegister(ModuleName, NowFuncName, func() facts.Fact { return &DateTimeFact{} }) // must register the fact and name } // DateTimeFact is a fact which returns the current date and time. @@ -34,6 +40,12 @@ type DateTimeFact struct { closeChan chan struct{} } +// String returns a simple name for this fact. This is needed so this struct can +// satisfy the pgraph.Vertex interface. +func (obj *DateTimeFact) String() string { + return NowFuncName +} + // Validate makes sure we've built our struct properly. It is usually unused for // normal facts that users can use directly. //func (obj *DateTimeFact) Validate() error { diff --git a/lang/funcs/core/deploy/abspath_func.go b/lang/funcs/core/deploy/abspath_func.go index 0fdf2054..af22c956 100644 --- a/lang/funcs/core/deploy/abspath_func.go +++ b/lang/funcs/core/deploy/abspath_func.go @@ -26,14 +26,17 @@ import ( "github.com/purpleidea/mgmt/lang/types" ) +const ( + // AbsPathFuncName is the name this function is registered as. + AbsPathFuncName = "abspath" + + pathArg = "path" +) + func init() { funcs.ModuleRegister(ModuleName, "abspath", func() interfaces.Func { return &AbsPathFunc{} }) // must register the func and name } -const ( - pathArg = "path" -) - // AbsPathFunc is a function that returns the absolute, full path in the deploy // from an input path that is relative to the calling file. If you pass it an // empty string, you'll just get the absolute deploy directory path that you're @@ -49,6 +52,12 @@ type AbsPathFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *AbsPathFunc) String() string { + return AbsPathFuncName +} + // SetData is used by the language to pass our function some code-level context. func (obj *AbsPathFunc) SetData(data *interfaces.FuncData) { obj.data = data diff --git a/lang/funcs/core/deploy/readfile_func.go b/lang/funcs/core/deploy/readfile_func.go index b3e74ed9..176d6ebe 100644 --- a/lang/funcs/core/deploy/readfile_func.go +++ b/lang/funcs/core/deploy/readfile_func.go @@ -27,8 +27,13 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // ReadFileFuncName is the name this function is registered as. + ReadFileFuncName = "readfile" +) + func init() { - funcs.ModuleRegister(ModuleName, "readfile", func() interfaces.Func { return &ReadFileFunc{} }) // must register the func and name + funcs.ModuleRegister(ModuleName, ReadFileFuncName, func() interfaces.Func { return &ReadFileFunc{} }) // must register the func and name } // ReadFileFunc is a function that reads the full contents from a file in our @@ -46,6 +51,12 @@ type ReadFileFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *ReadFileFunc) String() string { + return ReadFileFuncName +} + // SetData is used by the language to pass our function some code-level context. func (obj *ReadFileFunc) SetData(data *interfaces.FuncData) { obj.data = data diff --git a/lang/funcs/core/deploy/readfileabs_func.go b/lang/funcs/core/deploy/readfileabs_func.go index 2e6d93ac..0f9fb748 100644 --- a/lang/funcs/core/deploy/readfileabs_func.go +++ b/lang/funcs/core/deploy/readfileabs_func.go @@ -26,8 +26,13 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // ReadFileAbsFuncName is the name this function is registered as. + ReadFileAbsFuncName = "readfileabs" +) + func init() { - funcs.ModuleRegister(ModuleName, "readfileabs", func() interfaces.Func { return &ReadFileAbsFunc{} }) // must register the func and name + funcs.ModuleRegister(ModuleName, ReadFileAbsFuncName, func() interfaces.Func { return &ReadFileAbsFunc{} }) // must register the func and name } // ReadFileAbsFunc is a function that reads the full contents from a file in our @@ -46,6 +51,12 @@ type ReadFileAbsFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *ReadFileAbsFunc) String() string { + return ReadFileAbsFuncName +} + // SetData is used by the language to pass our function some code-level context. func (obj *ReadFileAbsFunc) SetData(data *interfaces.FuncData) { obj.data = data diff --git a/lang/funcs/core/example/flipflop_fact.go b/lang/funcs/core/example/flipflop_fact.go index cdd38bfa..45a320f5 100644 --- a/lang/funcs/core/example/flipflop_fact.go +++ b/lang/funcs/core/example/flipflop_fact.go @@ -24,8 +24,14 @@ import ( "github.com/purpleidea/mgmt/lang/types" ) +const ( + // FlipFlopFuncName is the name this fact is registered as. It's still a + // Func Name because this is the name space the fact is actually using. + FlipFlopFuncName = "flipflop" +) + func init() { - facts.ModuleRegister(ModuleName, "flipflop", func() facts.Fact { return &FlipFlopFact{} }) // must register the fact and name + facts.ModuleRegister(ModuleName, FlipFlopFuncName, func() facts.Fact { return &FlipFlopFact{} }) // must register the fact and name } // FlipFlopFact is a fact which flips a bool repeatedly. This is an example fact @@ -37,6 +43,12 @@ type FlipFlopFact struct { closeChan chan struct{} } +// String returns a simple name for this fact. This is needed so this struct can +// satisfy the pgraph.Vertex interface. +func (obj *FlipFlopFact) String() string { + return FlipFlopFuncName +} + // Validate makes sure we've built our struct properly. It is usually unused for // normal facts that users can use directly. //func (obj *FlipFlopFact) Validate() error { diff --git a/lang/funcs/core/example/vumeter_func.go b/lang/funcs/core/example/vumeter_func.go index c4bdff95..55142fa7 100644 --- a/lang/funcs/core/example/vumeter_func.go +++ b/lang/funcs/core/example/vumeter_func.go @@ -35,8 +35,13 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // VUMeterFuncName is the name this function is registered as. + VUMeterFuncName = "vumeter" +) + func init() { - funcs.ModuleRegister(ModuleName, "vumeter", func() interfaces.Func { return &VUMeterFunc{} }) // must register the func and name + funcs.ModuleRegister(ModuleName, VUMeterFuncName, func() interfaces.Func { return &VUMeterFunc{} }) // must register the func and name } // VUMeterFunc is a gimmic function to display a vu meter from the microphone. @@ -53,6 +58,12 @@ type VUMeterFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *VUMeterFunc) String() string { + return VUMeterFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *VUMeterFunc) ArgGen(index int) (string, error) { seq := []string{"symbol", "multiplier", "peak"} diff --git a/lang/funcs/core/fmt/printf_func.go b/lang/funcs/core/fmt/printf_func.go index f8f34a68..7d9f06e8 100644 --- a/lang/funcs/core/fmt/printf_func.go +++ b/lang/funcs/core/fmt/printf_func.go @@ -27,15 +27,18 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) -func init() { - // FIXME: should this be named sprintf instead? - funcs.ModuleRegister(ModuleName, "printf", func() interfaces.Func { return &PrintfFunc{} }) -} - const ( + // PrintfFuncName is the name this function is registered as. + // FIXME: should this be named sprintf instead? + PrintfFuncName = "printf" + formatArgName = "format" // name of the first arg ) +func init() { + funcs.ModuleRegister(ModuleName, PrintfFuncName, func() interfaces.Func { return &PrintfFunc{} }) +} + // PrintfFunc is a static polymorphic function that compiles a format string and // returns the output as a string. It bases its output on the values passed in // to it. It examines the type of the arguments at compile time and then @@ -56,6 +59,12 @@ type PrintfFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *PrintfFunc) String() string { + return PrintfFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *PrintfFunc) ArgGen(index int) (string, error) { if index == 0 { diff --git a/lang/funcs/core/iter/map_func.go b/lang/funcs/core/iter/map_func.go index 3abba2f3..970ec526 100644 --- a/lang/funcs/core/iter/map_func.go +++ b/lang/funcs/core/iter/map_func.go @@ -27,9 +27,14 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) -func init() { +const ( + // MapFuncName is the name this function is registered as. // XXX: rename to map once our parser sees a function name and not a type - funcs.ModuleRegister(ModuleName, "xmap", func() interfaces.Func { return &MapFunc{} }) // must register the func and name + MapFuncName = "xmap" +) + +func init() { + funcs.ModuleRegister(ModuleName, MapFuncName, func() interfaces.Func { return &MapFunc{} }) // must register the func and name } const ( @@ -62,6 +67,12 @@ type MapFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *MapFunc) String() string { + return MapFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *MapFunc) ArgGen(index int) (string, error) { seq := []string{argNameInputs, argNameFunction} // inverted for pretty! diff --git a/lang/funcs/core/os/readfile_func.go b/lang/funcs/core/os/readfile_func.go index 66394388..48201886 100644 --- a/lang/funcs/core/os/readfile_func.go +++ b/lang/funcs/core/os/readfile_func.go @@ -29,8 +29,13 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // ReadFileFuncName is the name this function is registered as. + ReadFileFuncName = "readfile" +) + func init() { - funcs.ModuleRegister(ModuleName, "readfile", func() interfaces.Func { return &ReadFileFunc{} }) // must register the func and name + funcs.ModuleRegister(ModuleName, ReadFileFuncName, func() interfaces.Func { return &ReadFileFunc{} }) // must register the func and name } // ReadFileFunc is a function that reads the full contents from a local file. If @@ -51,6 +56,12 @@ type ReadFileFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *ReadFileFunc) String() string { + return ReadFileFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *ReadFileFunc) ArgGen(index int) (string, error) { seq := []string{"filename"} diff --git a/lang/funcs/core/os/system_func.go b/lang/funcs/core/os/system_func.go index e7cfd5c3..ceb8bdf8 100644 --- a/lang/funcs/core/os/system_func.go +++ b/lang/funcs/core/os/system_func.go @@ -29,8 +29,13 @@ import ( "github.com/purpleidea/mgmt/lang/types" ) +const ( + // SystemFuncName is the name this function is registered as. + SystemFuncName = "system" +) + func init() { - funcs.ModuleRegister(ModuleName, "system", func() interfaces.Func { return &SystemFunc{} }) + funcs.ModuleRegister(ModuleName, SystemFuncName, func() interfaces.Func { return &SystemFunc{} }) } // SystemFunc runs a string as a shell command, then produces each line from @@ -47,6 +52,12 @@ type SystemFunc struct { cancel context.CancelFunc } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *SystemFunc) String() string { + return SystemFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *SystemFunc) ArgGen(index int) (string, error) { seq := []string{"shell_command"} diff --git a/lang/funcs/core/random1_func.go b/lang/funcs/core/random1_func.go index 02205aa6..9cd8cd9c 100644 --- a/lang/funcs/core/random1_func.go +++ b/lang/funcs/core/random1_func.go @@ -28,10 +28,15 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) -const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +const ( + // Random1FuncName is the name this function is registered as. + Random1FuncName = "random1" + + alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +) func init() { - funcs.Register("random1", func() interfaces.Func { return &Random1Func{} }) + funcs.Register(Random1FuncName, func() interfaces.Func { return &Random1Func{} }) } // Random1Func returns one random string of a certain length. @@ -52,6 +57,12 @@ type Random1Func struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *Random1Func) String() string { + return Random1FuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *Random1Func) ArgGen(index int) (string, error) { seq := []string{"length"} diff --git a/lang/funcs/core/sys/cpucount_fact.go b/lang/funcs/core/sys/cpucount_fact.go index e4b7ef13..af3d60a0 100644 --- a/lang/funcs/core/sys/cpucount_fact.go +++ b/lang/funcs/core/sys/cpucount_fact.go @@ -35,13 +35,17 @@ import ( ) const ( + // CPUCountFuncName is the name this fact is registered as. It's still a + // Func Name because this is the name space the fact is actually using. + CPUCountFuncName = "cpu_count" + rtmGrps = 0x1 // make me a multicast receiver socketFile = "pipe.sock" cpuDevpathRegex = "/devices/system/cpu/cpu[0-9]" ) func init() { - facts.ModuleRegister(ModuleName, "cpu_count", func() facts.Fact { return &CPUCountFact{} }) // must register the fact and name + facts.ModuleRegister(ModuleName, CPUCountFuncName, func() facts.Fact { return &CPUCountFact{} }) // must register the fact and name } // CPUCountFact is a fact that returns the current CPU count. @@ -50,6 +54,12 @@ type CPUCountFact struct { closeChan chan struct{} } +// String returns a simple name for this fact. This is needed so this struct can +// satisfy the pgraph.Vertex interface. +func (obj *CPUCountFact) String() string { + return CPUCountFuncName +} + // Info returns static typing info about what the fact returns. func (obj *CPUCountFact) Info() *facts.Info { return &facts.Info{ diff --git a/lang/funcs/core/sys/hostname_fact.go b/lang/funcs/core/sys/hostname_fact.go index a6899429..ee9bbf97 100644 --- a/lang/funcs/core/sys/hostname_fact.go +++ b/lang/funcs/core/sys/hostname_fact.go @@ -22,8 +22,14 @@ import ( "github.com/purpleidea/mgmt/lang/types" ) +const ( + // HostnameFuncName is the name this fact is registered as. It's still a + // Func Name because this is the name space the fact is actually using. + HostnameFuncName = "hostname" +) + func init() { - facts.ModuleRegister(ModuleName, "hostname", func() facts.Fact { return &HostnameFact{} }) // must register the fact and name + facts.ModuleRegister(ModuleName, HostnameFuncName, func() facts.Fact { return &HostnameFact{} }) // must register the fact and name } // HostnameFact is a function that returns the hostname. @@ -33,6 +39,12 @@ type HostnameFact struct { closeChan chan struct{} } +// String returns a simple name for this fact. This is needed so this struct can +// satisfy the pgraph.Vertex interface. +func (obj *HostnameFact) String() string { + return HostnameFuncName +} + // Validate makes sure we've built our struct properly. It is usually unused for // normal facts that users can use directly. //func (obj *HostnameFact) Validate() error { diff --git a/lang/funcs/core/sys/load_fact.go b/lang/funcs/core/sys/load_fact.go index 6b8e5dc9..5ea49370 100644 --- a/lang/funcs/core/sys/load_fact.go +++ b/lang/funcs/core/sys/load_fact.go @@ -26,11 +26,15 @@ import ( ) const ( + // LoadFuncName is the name this fact is registered as. It's still a + // Func Name because this is the name space the fact is actually using. + LoadFuncName = "load" + loadSignature = "struct{x1 float; x5 float; x15 float}" ) func init() { - facts.ModuleRegister(ModuleName, "load", func() facts.Fact { return &LoadFact{} }) // must register the fact and name + facts.ModuleRegister(ModuleName, LoadFuncName, func() facts.Fact { return &LoadFact{} }) // must register the fact and name } // LoadFact is a fact which returns the current system load. @@ -39,6 +43,12 @@ type LoadFact struct { closeChan chan struct{} } +// String returns a simple name for this fact. This is needed so this struct can +// satisfy the pgraph.Vertex interface. +func (obj *LoadFact) String() string { + return LoadFuncName +} + // Validate makes sure we've built our struct properly. It is usually unused for // normal facts that users can use directly. //func (obj *LoadFact) Validate() error { diff --git a/lang/funcs/core/sys/uptime_fact.go b/lang/funcs/core/sys/uptime_fact.go index bfe17290..b3694b74 100644 --- a/lang/funcs/core/sys/uptime_fact.go +++ b/lang/funcs/core/sys/uptime_fact.go @@ -25,8 +25,14 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // UptimeFuncName is the name this fact is registered as. It's still a + // Func Name because this is the name space the fact is actually using. + UptimeFuncName = "uptime" +) + func init() { - facts.ModuleRegister(ModuleName, "uptime", func() facts.Fact { return &UptimeFact{} }) + facts.ModuleRegister(ModuleName, UptimeFuncName, func() facts.Fact { return &UptimeFact{} }) } // UptimeFact is a fact which returns the current uptime of your system. @@ -35,6 +41,12 @@ type UptimeFact struct { closeChan chan struct{} } +// String returns a simple name for this fact. This is needed so this struct can +// satisfy the pgraph.Vertex interface. +func (obj *UptimeFact) String() string { + return UptimeFuncName +} + // Info returns some static info about itself. func (obj *UptimeFact) Info() *facts.Info { return &facts.Info{ diff --git a/lang/funcs/core/template_func.go b/lang/funcs/core/template_func.go index 2b0622c2..f3b52bb6 100644 --- a/lang/funcs/core/template_func.go +++ b/lang/funcs/core/template_func.go @@ -31,17 +31,10 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) -var ( - // errorType represents a reflection type of error as seen in: - // https://github.com/golang/go/blob/ec62ee7f6d3839fe69aeae538dadc1c9dc3bf020/src/text/template/exec.go#L612 - errorType = reflect.TypeOf((*error)(nil)).Elem() -) - -func init() { - funcs.Register("template", func() interfaces.Func { return &TemplateFunc{} }) -} - const ( + // TemplateFuncName is the name this function is registered as. + TemplateFuncName = "template" + // TemplateName is the name of our template as required by the template // library. TemplateName = "template" @@ -50,6 +43,16 @@ const ( argNameVars = "vars" ) +var ( + // errorType represents a reflection type of error as seen in: + // https://github.com/golang/go/blob/ec62ee7f6d3839fe69aeae538dadc1c9dc3bf020/src/text/template/exec.go#L612 + errorType = reflect.TypeOf((*error)(nil)).Elem() +) + +func init() { + funcs.Register(TemplateFuncName, func() interfaces.Func { return &TemplateFunc{} }) +} + // TemplateFunc is a static polymorphic function that compiles a template and // returns the output as a string. It bases its output on the values passed in // to it. It examines the type of the second argument (the input data vars) at @@ -73,6 +76,12 @@ type TemplateFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *TemplateFunc) String() string { + return TemplateFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *TemplateFunc) ArgGen(index int) (string, error) { seq := []string{argNameTemplate, argNameVars} diff --git a/lang/funcs/core/world/exchange_func.go b/lang/funcs/core/world/exchange_func.go index 92c7fc39..f7e3375c 100644 --- a/lang/funcs/core/world/exchange_func.go +++ b/lang/funcs/core/world/exchange_func.go @@ -27,8 +27,13 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // ExchangeFuncName is the name this function is registered as. + ExchangeFuncName = "exchange" +) + func init() { - funcs.ModuleRegister(ModuleName, "exchange", func() interfaces.Func { return &ExchangeFunc{} }) + funcs.ModuleRegister(ModuleName, ExchangeFuncName, func() interfaces.Func { return &ExchangeFunc{} }) } // ExchangeFunc is special function which returns all the values of a given key @@ -46,6 +51,12 @@ type ExchangeFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *ExchangeFunc) String() string { + return ExchangeFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *ExchangeFunc) ArgGen(index int) (string, error) { seq := []string{"namespace", "value"} diff --git a/lang/funcs/core/world/kvlookup_func.go b/lang/funcs/core/world/kvlookup_func.go index ff288c6c..2ce7b143 100644 --- a/lang/funcs/core/world/kvlookup_func.go +++ b/lang/funcs/core/world/kvlookup_func.go @@ -27,8 +27,13 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // KVLookupFuncName is the name this function is registered as. + KVLookupFuncName = "kvlookup" +) + func init() { - funcs.ModuleRegister(ModuleName, "kvlookup", func() interfaces.Func { return &KVLookupFunc{} }) + funcs.ModuleRegister(ModuleName, KVLookupFuncName, func() interfaces.Func { return &KVLookupFunc{} }) } // KVLookupFunc is special function which returns all the values of a given key @@ -46,6 +51,12 @@ type KVLookupFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *KVLookupFunc) String() string { + return KVLookupFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *KVLookupFunc) ArgGen(index int) (string, error) { seq := []string{"namespace"} diff --git a/lang/funcs/core/world/schedule_func.go b/lang/funcs/core/world/schedule_func.go index 2ff8f06f..f39b67dc 100644 --- a/lang/funcs/core/world/schedule_func.go +++ b/lang/funcs/core/world/schedule_func.go @@ -42,6 +42,9 @@ import ( ) const ( + // ScheduleFuncName is the name this function is registered as. + ScheduleFuncName = "schedule" + // DefaultStrategy is the strategy to use if none has been specified. DefaultStrategy = "rr" @@ -58,7 +61,7 @@ const ( ) func init() { - funcs.ModuleRegister(ModuleName, "schedule", func() interfaces.Func { return &SchedulePolyFunc{} }) + funcs.ModuleRegister(ModuleName, ScheduleFuncName, func() interfaces.Func { return &SchedulePolyFunc{} }) } // SchedulePolyFunc is special function which determines where code should run @@ -80,6 +83,12 @@ type SchedulePolyFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *SchedulePolyFunc) String() string { + return ScheduleFuncName +} + // validOpts returns the available mapping of valid opts fields to types. func (obj *SchedulePolyFunc) validOpts() map[string]*types.Type { return map[string]*types.Type{ diff --git a/lang/funcs/facts/facts.go b/lang/funcs/facts/facts.go index 417939ad..78f3e2ef 100644 --- a/lang/funcs/facts/facts.go +++ b/lang/funcs/facts/facts.go @@ -79,6 +79,7 @@ type Init struct { // never change to avoid the overhead of the goroutine and channel listener? // TODO: should we move this to the interface package? type Fact interface { + String() string //Validate() error // currently not needed since no facts are internal Info() *Info Init(*Init) error diff --git a/lang/funcs/facts/func.go b/lang/funcs/facts/func.go index 9adad7c7..4601dfdd 100644 --- a/lang/funcs/facts/func.go +++ b/lang/funcs/facts/func.go @@ -30,6 +30,12 @@ type FactFunc struct { // implements `interfaces.Func` Fact Fact } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *FactFunc) String() string { + return obj.Fact.String() +} + // Validate makes sure we've built our struct properly. func (obj *FactFunc) Validate() error { if obj.Fact == nil { diff --git a/lang/funcs/history_polyfunc.go b/lang/funcs/history_polyfunc.go index dcaa5ae4..7bfb87e8 100644 --- a/lang/funcs/history_polyfunc.go +++ b/lang/funcs/history_polyfunc.go @@ -58,6 +58,12 @@ type HistoryFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *HistoryFunc) String() string { + return HistoryFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *HistoryFunc) ArgGen(index int) (string, error) { seq := []string{"value", "index"} diff --git a/lang/funcs/maplookup_polyfunc.go b/lang/funcs/maplookup_polyfunc.go index 89436353..8d1c1cd8 100644 --- a/lang/funcs/maplookup_polyfunc.go +++ b/lang/funcs/maplookup_polyfunc.go @@ -52,6 +52,12 @@ type MapLookupPolyFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *MapLookupPolyFunc) String() string { + return MapLookupFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *MapLookupPolyFunc) ArgGen(index int) (string, error) { seq := []string{argNameMap, argNameKey, argNameDef} diff --git a/lang/funcs/operator_polyfunc.go b/lang/funcs/operator_polyfunc.go index f82430a7..741d85ed 100644 --- a/lang/funcs/operator_polyfunc.go +++ b/lang/funcs/operator_polyfunc.go @@ -435,6 +435,13 @@ type OperatorPolyFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *OperatorPolyFunc) String() string { + // TODO: return the exact operator if we can guarantee it doesn't change + return OperatorFuncName +} + // argNames returns the maximum list of possible argNames. This can be truncated // if needed. The first arg name is the operator. func (obj *OperatorPolyFunc) argNames() ([]string, error) { diff --git a/lang/funcs/simple/simple.go b/lang/funcs/simple/simple.go index d84d8ad9..880d2ba0 100644 --- a/lang/funcs/simple/simple.go +++ b/lang/funcs/simple/simple.go @@ -58,7 +58,7 @@ func Register(name string, fn *types.FuncValue) { RegisteredFuncs[name] = fn // store a copy for ourselves // register a copy in the main function database - funcs.Register(name, func() interfaces.Func { return &WrappedFunc{Fn: fn} }) + funcs.Register(name, func() interfaces.Func { return &WrappedFunc{Name: name, Fn: fn} }) } // ModuleRegister is exactly like Register, except that it registers within a @@ -70,6 +70,8 @@ func ModuleRegister(module, name string, fn *types.FuncValue) { // WrappedFunc is a scaffolding function struct which fulfills the boiler-plate // for the function API, but that can run a very simple, static, pure function. type WrappedFunc struct { + Name string + Fn *types.FuncValue init *interfaces.Init @@ -80,6 +82,12 @@ type WrappedFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *WrappedFunc) String() string { + return obj.Name +} + // ArgGen returns the Nth arg name for this function. func (obj *WrappedFunc) ArgGen(index int) (string, error) { typ := obj.Fn.Type() diff --git a/lang/funcs/simplepoly/simplepoly.go b/lang/funcs/simplepoly/simplepoly.go index 30c498e7..6ab85114 100644 --- a/lang/funcs/simplepoly/simplepoly.go +++ b/lang/funcs/simplepoly/simplepoly.go @@ -90,7 +90,7 @@ func Register(name string, fns []*types.FuncValue) { RegisteredFuncs[name] = fns // store a copy for ourselves // register a copy in the main function database - funcs.Register(name, func() interfaces.Func { return &WrappedFunc{Fns: fns} }) + funcs.Register(name, func() interfaces.Func { return &WrappedFunc{Name: name, Fns: fns} }) } // ModuleRegister is exactly like Register, except that it registers within a @@ -131,6 +131,8 @@ func consistentArgs(fns []*types.FuncValue) ([]string, error) { // for the function API, but that can run a very simple, static, pure, // polymorphic function. type WrappedFunc struct { + Name string + Fns []*types.FuncValue // list of possible functions fn *types.FuncValue // the concrete version of our chosen function @@ -143,6 +145,12 @@ type WrappedFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *WrappedFunc) String() string { + return obj.Name +} + // ArgGen returns the Nth arg name for this function. func (obj *WrappedFunc) ArgGen(index int) (string, error) { seq, err := consistentArgs(obj.Fns) diff --git a/lang/funcs/structlookup_polyfunc.go b/lang/funcs/structlookup_polyfunc.go index 375c03fd..64e02d0d 100644 --- a/lang/funcs/structlookup_polyfunc.go +++ b/lang/funcs/structlookup_polyfunc.go @@ -50,6 +50,12 @@ type StructLookupPolyFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *StructLookupPolyFunc) String() string { + return StructLookupFuncName +} + // ArgGen returns the Nth arg name for this function. func (obj *StructLookupPolyFunc) ArgGen(index int) (string, error) { seq := []string{"struct", "field"} diff --git a/lang/funcs/structs/call.go b/lang/funcs/structs/call.go index e35af2f1..194009a0 100644 --- a/lang/funcs/structs/call.go +++ b/lang/funcs/structs/call.go @@ -25,6 +25,11 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // CallFuncName is the unique name identifier for this function. + CallFuncName = "call" +) + // CallFunc is a function that takes in a function and all the args, and passes // through the results of running the function call. type CallFunc struct { @@ -45,6 +50,12 @@ type CallFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *CallFunc) String() string { + return CallFuncName +} + // Validate makes sure we've built our struct properly. func (obj *CallFunc) Validate() error { if obj.Type == nil { diff --git a/lang/funcs/structs/composite.go b/lang/funcs/structs/composite.go index 7af7f679..58dbe604 100644 --- a/lang/funcs/structs/composite.go +++ b/lang/funcs/structs/composite.go @@ -25,6 +25,11 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // CompositeFuncName is the unique name identifier for this function. + CompositeFuncName = "composite" +) + // CompositeFunc is a function that passes through the value it receives. It is // used to take a series of inputs to a list, map or struct, and return that // value as a stream that depends on those inputs. It helps the list, map, and @@ -40,6 +45,12 @@ type CompositeFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *CompositeFunc) String() string { + return CompositeFuncName +} + // Validate makes sure we've built our struct properly. func (obj *CompositeFunc) Validate() error { if obj.Type == nil { diff --git a/lang/funcs/structs/const.go b/lang/funcs/structs/const.go index e89e18a5..280e576f 100644 --- a/lang/funcs/structs/const.go +++ b/lang/funcs/structs/const.go @@ -24,6 +24,11 @@ import ( "github.com/purpleidea/mgmt/lang/types" ) +const ( + // ConstFuncName is the unique name identifier for this function. + ConstFuncName = "const" +) + // ConstFunc is a function that returns the constant value passed to Value. type ConstFunc struct { Value types.Value @@ -32,6 +37,12 @@ type ConstFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *ConstFunc) String() string { + return ConstFuncName +} + // Validate makes sure we've built our struct properly. func (obj *ConstFunc) Validate() error { if obj.Value == nil { diff --git a/lang/funcs/structs/function.go b/lang/funcs/structs/function.go index e26f7bbb..38d6cf0d 100644 --- a/lang/funcs/structs/function.go +++ b/lang/funcs/structs/function.go @@ -26,6 +26,11 @@ import ( "github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // FunctionFuncName is the unique name identifier for this function. + FunctionFuncName = "function" +) + // FunctionFunc is a function that passes through the function body it receives. type FunctionFunc struct { Type *types.Type // this is the type of the function that we hold @@ -40,6 +45,12 @@ type FunctionFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *FunctionFunc) String() string { + return FunctionFuncName +} + // fn returns the function that wraps the Func interface if that API is used. func (obj *FunctionFunc) fn() (*types.FuncValue, error) { fn := func(args []types.Value) (types.Value, error) { diff --git a/lang/funcs/structs/if.go b/lang/funcs/structs/if.go index dade9f44..d177970b 100644 --- a/lang/funcs/structs/if.go +++ b/lang/funcs/structs/if.go @@ -24,6 +24,11 @@ import ( "github.com/purpleidea/mgmt/lang/types" ) +const ( + // IfFuncName is the unique name identifier for this function. + IfFuncName = "if" +) + // IfFunc is a function that passes through the value of the correct branch // based on the conditional value it gets. type IfFunc struct { @@ -36,6 +41,12 @@ type IfFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *IfFunc) String() string { + return IfFuncName +} + // Validate tells us if the input struct takes a valid form. func (obj *IfFunc) Validate() error { if obj.Type == nil { diff --git a/lang/funcs/structs/var.go b/lang/funcs/structs/var.go index faf075f8..0481d5ff 100644 --- a/lang/funcs/structs/var.go +++ b/lang/funcs/structs/var.go @@ -25,6 +25,11 @@ import ( //"github.com/purpleidea/mgmt/util/errwrap" ) +const ( + // VarFuncName is the unique name identifier for this function. + VarFuncName = "var" +) + // VarFunc is a function that passes through a function that came from a bind // lookup. It exists so that the reactive function engine type checks correctly. type VarFunc struct { @@ -39,6 +44,12 @@ type VarFunc struct { closeChan chan struct{} } +// String returns a simple name for this function. This is needed so this struct +// can satisfy the pgraph.Vertex interface. +func (obj *VarFunc) String() string { + return VarFuncName +} + // Validate makes sure we've built our struct properly. func (obj *VarFunc) Validate() error { if obj.Type == nil { diff --git a/lang/interfaces/func.go b/lang/interfaces/func.go index 7d5aa922..5217e90b 100644 --- a/lang/interfaces/func.go +++ b/lang/interfaces/func.go @@ -18,6 +18,7 @@ package interfaces import ( + "fmt" "strings" "github.com/purpleidea/mgmt/engine" @@ -57,6 +58,8 @@ type Init struct { // TODO: should we support a static version of this interface for funcs that // never change to avoid the overhead of the goroutine and channel listener? type Func interface { + fmt.Stringer // so that this can be stored as a Vertex + Validate() error // FIXME: this is only needed for PolyFunc. Get it moved and used! // Info returns some information about the function in question, which