chore: allow decorator to split functions (#26357)
This commit is contained in:
parent
1e0539ec7d
commit
30b1e135e4
8 changed files with 903 additions and 11264 deletions
|
|
@ -32,6 +32,9 @@ import (
|
|||
//go:embed decorate.tpl
|
||||
var srcTmpl string
|
||||
|
||||
//go:embed header.tpl
|
||||
var header string
|
||||
|
||||
type dynamicType struct {
|
||||
typ, function, signature string
|
||||
}
|
||||
|
|
@ -85,7 +88,7 @@ func hasIntersection[T comparable](a, b []T) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func generate(out io.Writer, packageName, functionName, baseType string, dynamicTypes ...dynamicType) error {
|
||||
func generate(out io.Writer, functionName, baseType string, dynamicTypes ...dynamicType) error {
|
||||
types := make(map[string]typeStruct, len(dynamicTypes))
|
||||
combos := make([]string, 0)
|
||||
|
||||
|
|
@ -186,15 +189,12 @@ COMBO:
|
|||
}
|
||||
|
||||
vars := struct {
|
||||
API string
|
||||
Package, Function string
|
||||
Function string
|
||||
BaseType, ShortBase string
|
||||
ReturnType string
|
||||
Types map[string]typeStruct
|
||||
Combinations [][]string
|
||||
}{
|
||||
API: "github.com/evcc-io/evcc/api",
|
||||
Package: packageName,
|
||||
Function: functionName,
|
||||
BaseType: baseType,
|
||||
ShortBase: shortBase,
|
||||
|
|
@ -206,6 +206,11 @@ COMBO:
|
|||
return tmpl.Execute(out, vars)
|
||||
}
|
||||
|
||||
type decorationSet struct {
|
||||
function, base, ret string
|
||||
types []string
|
||||
}
|
||||
|
||||
var (
|
||||
target = pflag.StringP("out", "o", "", "output file")
|
||||
pkg = pflag.StringP("package", "p", "", "package name")
|
||||
|
|
@ -223,13 +228,17 @@ func Usage() {
|
|||
pflag.PrintDefaults()
|
||||
}
|
||||
|
||||
func parseFile(file string, function, basetype, returntype *string, types *[]string) error {
|
||||
func parseFile(file string) ([]decorationSet, error) {
|
||||
var res []decorationSet
|
||||
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var current decorationSet
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
|
@ -242,20 +251,29 @@ func parseFile(file string, function, basetype, returntype *string, types *[]str
|
|||
|
||||
switch segs[0] {
|
||||
case "function":
|
||||
*function = segs[1]
|
||||
// must be first
|
||||
if current.function != "" {
|
||||
res = append(res, current)
|
||||
current = decorationSet{}
|
||||
}
|
||||
current.function = segs[1]
|
||||
case "basetype":
|
||||
*basetype = segs[1]
|
||||
current.base = segs[1]
|
||||
case "returntype":
|
||||
*returntype = segs[1]
|
||||
current.ret = segs[1]
|
||||
case "type":
|
||||
*types = append(*types, segs[1])
|
||||
current.types = append(current.types, segs[1])
|
||||
default:
|
||||
panic("invalid directive //evcc:" + segs[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return scanner.Err()
|
||||
if current.function != "" {
|
||||
res = append(res, current)
|
||||
}
|
||||
|
||||
return res, scanner.Err()
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
@ -274,32 +292,22 @@ func main() {
|
|||
pkg = &gopkg
|
||||
}
|
||||
|
||||
sets := []decorationSet{{*function, *base, *ret, *types}}
|
||||
|
||||
if *function == "" {
|
||||
if err := parseFile(gofile, function, base, ret, types); err != nil {
|
||||
all, err := parseFile(gofile)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(2)
|
||||
}
|
||||
sets = all
|
||||
}
|
||||
|
||||
if *base == "" || *pkg == "" || len(*types) == 0 {
|
||||
if *pkg == "" || len(sets) == 0 || sets[0].base == "" || len(sets[0].types) == 0 {
|
||||
Usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
var dynamicTypes []dynamicType
|
||||
for _, v := range *types {
|
||||
split := strings.SplitN(v, ",", 3)
|
||||
dt := dynamicType{split[0], split[1], split[2]}
|
||||
dynamicTypes = append(dynamicTypes, dt)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := generate(&buf, *pkg, *function, *base, dynamicTypes...); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(2)
|
||||
}
|
||||
generated := strings.TrimSpace(buf.String()) + "\n"
|
||||
|
||||
var out io.Writer = os.Stdout
|
||||
|
||||
var name string
|
||||
|
|
@ -319,9 +327,29 @@ func main() {
|
|||
out = dst
|
||||
}
|
||||
|
||||
formatted, err := format.Source([]byte(generated))
|
||||
generated := new(bytes.Buffer)
|
||||
fmt.Fprintln(generated, strings.ReplaceAll(header, "{{.Package}}", *pkg))
|
||||
|
||||
for _, set := range sets {
|
||||
var dynamicTypes []dynamicType
|
||||
for _, v := range set.types {
|
||||
split := strings.SplitN(v, ",", 3)
|
||||
dt := dynamicType{split[0], split[1], split[2]}
|
||||
dynamicTypes = append(dynamicTypes, dt)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := generate(&buf, set.function, set.base, dynamicTypes...); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
fmt.Fprintln(generated, buf.String())
|
||||
}
|
||||
|
||||
formatted, err := format.Source(generated.Bytes())
|
||||
if err != nil {
|
||||
formatted = []byte(generated)
|
||||
formatted = generated.Bytes()
|
||||
}
|
||||
|
||||
formatted, err = imports.Process(name, formatted, nil)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
package {{.Package}}
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"{{.API}}"
|
||||
)
|
||||
|
||||
{{define "case"}}
|
||||
{{- $combo := .Combo}}
|
||||
{{- $prefix := .Prefix}}
|
||||
|
|
|
|||
7
cmd/decorate/header.tpl
Normal file
7
cmd/decorate/header.tpl
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package {{.Package}}
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
|
@ -14,7 +14,24 @@ func init() {
|
|||
registry.AddCtx(api.Custom, NewConfigurableFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateMeter -b api.Meter -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseVoltages,Voltages,func() (float64, float64, float64, error)" -t "api.PhasePowers,Powers,func() (float64, float64, float64, error)" -t "api.Battery,Soc,func() (float64, error)" -t "api.BatteryCapacity,Capacity,func() float64" -t "api.BatterySocLimiter,GetSocLimits,func() (float64, float64)" -t "api.BatteryPowerLimiter,GetPowerLimits,func() (float64, float64)" -t "api.BatteryController,SetBatteryMode,func(api.BatteryMode) error" -t "api.MaxACPowerGetter,MaxACPower,func() float64"
|
||||
//go:generate go tool decorate
|
||||
|
||||
//evcc:function decorateMeter
|
||||
//evcc:basetype api.Meter
|
||||
//evcc:type api.MeterEnergy,TotalEnergy,func() (float64, error)
|
||||
//evcc:type api.PhaseCurrents,Currents,func() (float64, float64, float64, error)
|
||||
//evcc:type api.PhaseVoltages,Voltages,func() (float64, float64, float64, error)
|
||||
//evcc:type api.PhasePowers,Powers,func() (float64, float64, float64, error)
|
||||
//evcc:type api.MaxACPowerGetter,MaxACPower,func() float64
|
||||
|
||||
//evcc:function decorateMeterBattery
|
||||
//evcc:basetype api.Meter
|
||||
//evcc:type api.MeterEnergy,TotalEnergy,func() (float64, error)
|
||||
//evcc:type api.Battery,Soc,func() (float64, error)
|
||||
//evcc:type api.BatteryCapacity,Capacity,func() float64
|
||||
//evcc:type api.BatterySocLimiter,GetSocLimits,func() (float64, float64)
|
||||
//evcc:type api.BatteryPowerLimiter,GetPowerLimits,func() (float64, float64)
|
||||
//evcc:type api.BatteryController,SetBatteryMode,func(api.BatteryMode) error
|
||||
|
||||
// NewConfigurableFromConfig creates api.Meter from config
|
||||
func NewConfigurableFromConfig(ctx context.Context, other map[string]any) (api.Meter, error) {
|
||||
|
|
@ -83,13 +100,18 @@ func NewConfigurableFromConfig(ctx context.Context, other map[string]any) (api.M
|
|||
}
|
||||
}
|
||||
|
||||
res := m.Decorate(
|
||||
energyG, currentsG, voltagesG, powersG,
|
||||
socG, cc.batteryCapacity.Decorator(), cc.batterySocLimits.Decorator(), cc.batteryPowerLimits.Decorator(), batModeS,
|
||||
cc.pvMaxACPower.Decorator(),
|
||||
)
|
||||
if socG != nil {
|
||||
return m.DecorateBattery(
|
||||
energyG,
|
||||
socG, cc.batteryCapacity.Decorator(),
|
||||
cc.batterySocLimits.Decorator(), cc.batteryPowerLimits.Decorator(),
|
||||
batModeS,
|
||||
), nil
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return m.Decorate(
|
||||
energyG, currentsG, voltagesG, powersG, cc.pvMaxACPower.Decorator(),
|
||||
), nil
|
||||
}
|
||||
|
||||
// NewConfigurable creates a new meter
|
||||
|
|
@ -109,19 +131,28 @@ type Meter struct {
|
|||
func (m *Meter) Decorate(
|
||||
totalEnergy func() (float64, error),
|
||||
currents, voltages, powers func() (float64, float64, float64, error),
|
||||
batterySoc func() (float64, error),
|
||||
batteryCapacity func() float64,
|
||||
batterySocLimits, batteryPowerLimits func() (float64, float64),
|
||||
setBatteryMode func(api.BatteryMode) error,
|
||||
maxACPower func() float64,
|
||||
) api.Meter {
|
||||
return decorateMeter(m,
|
||||
totalEnergy, currents, voltages, powers,
|
||||
batterySoc, batteryCapacity, batterySocLimits, batteryPowerLimits, setBatteryMode,
|
||||
maxACPower,
|
||||
)
|
||||
}
|
||||
|
||||
func (m *Meter) DecorateBattery(
|
||||
totalEnergy func() (float64, error),
|
||||
soc func() (float64, error), capacity func() float64,
|
||||
socLimits, powerLimits func() (float64, float64),
|
||||
setMode func(api.BatteryMode) error,
|
||||
) api.Meter {
|
||||
return decorateMeterBattery(m,
|
||||
totalEnergy,
|
||||
soc, capacity,
|
||||
socLimits, powerLimits,
|
||||
setMode,
|
||||
)
|
||||
}
|
||||
|
||||
// CurrentPower implements the api.Meter interface
|
||||
func (m *Meter) CurrentPower() (float64, error) {
|
||||
return m.currentPowerG()
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ func NewMovingAverageFromConfig(ctx context.Context, other map[string]any) (api.
|
|||
powers = m.Powers
|
||||
}
|
||||
|
||||
return meter.Decorate(totalEnergy, currents, voltages, powers, batterySoc, cc.Meter.batteryCapacity.Decorator(), nil, nil, nil, nil), nil
|
||||
if batterySoc != nil {
|
||||
return meter.DecorateBattery(totalEnergy, batterySoc, cc.Meter.batteryCapacity.Decorator(), nil, nil, nil), nil
|
||||
}
|
||||
|
||||
return meter.Decorate(totalEnergy, currents, voltages, powers, nil), nil
|
||||
}
|
||||
|
||||
type MovingAverage struct {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -8,22 +8,33 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestACPower(t *testing.T) {
|
||||
func TestPV(t *testing.T) {
|
||||
m, err := NewConfigurableFromConfig(t.Context(), map[string]any{
|
||||
"power": map[string]any{
|
||||
"source": "const",
|
||||
"value": 1000,
|
||||
},
|
||||
"maxacpower": 1000,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// must not have soc/capacity
|
||||
assert.Implements(t, new(api.MaxACPowerGetter), m)
|
||||
}
|
||||
func TestBattery(t *testing.T) {
|
||||
m, err := NewConfigurableFromConfig(t.Context(), map[string]any{
|
||||
"power": map[string]any{
|
||||
"source": "const",
|
||||
"value": 1000,
|
||||
},
|
||||
"capacity": 23,
|
||||
"soc": map[string]any{
|
||||
"source": "const",
|
||||
"value": 47,
|
||||
},
|
||||
"maxacpower": 1000,
|
||||
"power": map[string]any{
|
||||
"source": "const",
|
||||
"value": 1000,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, ok := m.(api.BatteryCapacity)
|
||||
assert.True(t, ok, "api.BatteryCapacity")
|
||||
_, ok = m.(api.MaxACPowerGetter)
|
||||
assert.True(t, ok, "api.MaxACPowerGetter")
|
||||
|
||||
assert.Implements(t, new(api.Battery), m)
|
||||
assert.Implements(t, new(api.BatteryCapacity), m)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,9 @@ func NewOpenWBFromConfig(other map[string]any) (api.Meter, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
res := m.Decorate(nil, currents, nil, nil, soc, capacity, nil, nil, nil, nil)
|
||||
if strings.ToLower(cc.Usage) == "battery" {
|
||||
return m.DecorateBattery(nil, soc, capacity, nil, nil, nil), nil
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return m.Decorate(nil, currents, nil, nil, nil), nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue