-
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #84 from daveshanley/custom-functions
Created new custom functions code.
- Loading branch information
Showing
13 changed files
with
296 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package plugin | ||
|
||
import ( | ||
"github.com/pterm/pterm" | ||
"io/ioutil" | ||
"path/filepath" | ||
"plugin" | ||
"strings" | ||
) | ||
|
||
// LoadFunctions will load custom functions found in the supplied path | ||
func LoadFunctions(path string) (*Manager, error) { | ||
|
||
dirEntries, err := ioutil.ReadDir(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
pm := createPluginManager() | ||
|
||
for _, entry := range dirEntries { | ||
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".so") { | ||
fPath := filepath.Join(path, entry.Name()) | ||
|
||
// found something | ||
pterm.Info.Printf("Located custom function plugin: %s\n", fPath) | ||
|
||
// let's try and open it. | ||
p, e := plugin.Open(fPath) | ||
if e != nil { | ||
return nil, e | ||
} | ||
|
||
// look up the Boot function and store as a Symbol | ||
var bootFunc plugin.Symbol | ||
bootFunc, e = p.Lookup("Boot") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// lets go pedro! | ||
if bootFunc != nil { | ||
bootFunc.(func(*Manager))(pm) | ||
} else { | ||
pterm.Error.Printf("Unable to boot plugin") | ||
} | ||
} | ||
} | ||
|
||
return pm, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package plugin | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"runtime" | ||
"testing" | ||
) | ||
|
||
func TestLoadFunctions_Nowhere(t *testing.T) { | ||
pm, err := LoadFunctions("nowhere") | ||
assert.Nil(t, pm) | ||
assert.Error(t, err) | ||
} | ||
|
||
func TestLoadFunctions(t *testing.T) { | ||
pm, err := LoadFunctions("../model/test_files") | ||
assert.NotNil(t, pm) | ||
assert.NoError(t, err) | ||
assert.Equal(t, 0, pm.LoadedFunctionCount()) | ||
} | ||
|
||
func TestLoadFunctions_Sample(t *testing.T) { | ||
pm, err := LoadFunctions("sample") | ||
if runtime.GOOS != "windows" { // windows does not support this feature, at all. | ||
assert.NotNil(t, pm) | ||
assert.NoError(t, err) | ||
assert.Equal(t, 0, pm.LoadedFunctionCount()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package plugin | ||
|
||
import ( | ||
"github.com/daveshanley/vacuum/model" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
type FunctionSchema func() model.RuleFunctionSchema | ||
type FunctionHook func(nodes []*yaml.Node, context model.RuleFunctionContext) []model.RuleFunctionResult | ||
|
||
type Manager struct { | ||
customFunctions map[string]model.RuleFunction | ||
} | ||
|
||
func createPluginManager() *Manager { | ||
return &Manager{ | ||
customFunctions: make(map[string]model.RuleFunction), | ||
} | ||
} | ||
|
||
// RegisterFunction allows a custom function to be hooked in | ||
func (pm *Manager) RegisterFunction(name string, ruleFunction model.RuleFunction) { | ||
pm.customFunctions[name] = ruleFunction | ||
} | ||
|
||
// LoadedFunctionCount returns the number of available and ready to use functions. | ||
func (pm *Manager) LoadedFunctionCount() int { | ||
return len(pm.customFunctions) | ||
} | ||
|
||
func (pm *Manager) GetCustomFunctions() map[string]model.RuleFunction { | ||
return pm.customFunctions | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package plugin | ||
|
||
import ( | ||
"github.com/daveshanley/vacuum/functions/core" | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestPluginManager_RegisterFunction(t *testing.T) { | ||
|
||
pm := createPluginManager() | ||
|
||
pm.RegisterFunction("defined", core.Defined{}) | ||
assert.Len(t, pm.GetCustomFunctions(), 1) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package main | ||
|
||
import "github.com/daveshanley/vacuum/plugin" | ||
|
||
// Boot is called by the Manager when the module is located. | ||
// all custom functions should be registered here. | ||
func Boot(pm *plugin.Manager) { | ||
|
||
sampleA := SampleRuleFunction_A{} | ||
sampleB := SampleRuleFunction_B{} | ||
|
||
// register custom functions with vacuum plugin manager. | ||
pm.RegisterFunction(sampleA.GetSchema().Name, sampleA) | ||
pm.RegisterFunction(sampleB.GetSchema().Name, sampleB) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/daveshanley/vacuum/model" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
// SampleRuleFunction_A is an example custom rule that does nothing. | ||
type SampleRuleFunction_A struct { | ||
} | ||
|
||
// GetSchema returns a model.RuleFunctionSchema defining the schema of the Defined rule. | ||
func (s SampleRuleFunction_A) GetSchema() model.RuleFunctionSchema { | ||
return model.RuleFunctionSchema{ | ||
Name: "uselessFunc", | ||
} | ||
} | ||
|
||
// RunRule will execute the Sample rule, based on supplied context and a supplied []*yaml.Node slice. | ||
func (s SampleRuleFunction_A) RunRule(nodes []*yaml.Node, context model.RuleFunctionContext) []model.RuleFunctionResult { | ||
|
||
// return a single result, for a made up linting failure. | ||
return []model.RuleFunctionResult{ | ||
{ | ||
Message: "this is a useless function that will always error out.", | ||
StartNode: &yaml.Node{Line: 1, Column: 0}, | ||
EndNode: &yaml.Node{Line: 2, Column: 0}, | ||
Path: "$.i.do.not.exist", | ||
Rule: context.Rule, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"github.com/daveshanley/vacuum/model" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
// SampleRuleFunction_B is an example custom rule that checks only a single path exists. | ||
type SampleRuleFunction_B struct { | ||
} | ||
|
||
// GetSchema returns a model.RuleFunctionSchema defining the schema of the Defined rule. | ||
func (s SampleRuleFunction_B) GetSchema() model.RuleFunctionSchema { | ||
return model.RuleFunctionSchema{ | ||
Name: "checkSinglePathExists", | ||
} | ||
} | ||
|
||
// RunRule will execute the Sample rule, based on supplied context and a supplied []*yaml.Node slice. | ||
func (s SampleRuleFunction_B) RunRule(nodes []*yaml.Node, context model.RuleFunctionContext) []model.RuleFunctionResult { | ||
|
||
// get the index https://quobix.com/vacuum/api/spec-index/ | ||
index := context.Index | ||
|
||
// get the paths node from the index. | ||
paths := index.GetPathsNode() | ||
|
||
// checks if there are more than two nodes present in the paths node, if so, more than one path is present. | ||
if len(paths.Content) > 2 { | ||
return []model.RuleFunctionResult{ | ||
{ | ||
Message: fmt.Sprintf("more than a single path exists, there are %v", len(paths.Content)/2), | ||
StartNode: paths, | ||
EndNode: paths, | ||
Path: "$.paths", | ||
Rule: context.Rule, | ||
}, | ||
} | ||
} | ||
return nil | ||
} |
Oops, something went wrong.