From e86c828380e1248f8c662265a15aa73ddb15d91a Mon Sep 17 00:00:00 2001 From: afti-githobo <31148582+afti-githobo@users.noreply.github.com> Date: Mon, 23 Jan 2023 08:39:07 -0800 Subject: [PATCH] Gadget hotfix (#1755) * Implement a very simple command to dump parsed recipe/cookbook data, to make debugging easier in the absence of nicer data validation stuff * Sometimes vscode doesn't save your file contents! That is fine and normal! * test + provisional bugfix * gofumpt * fix this test * fix the regex... --- cmd/pylonsd/cmd/dev.go | 19 ++++++++++++++----- cmd/pylonsd/cmd/dev_parse.go | 25 +++++++++++++++++++++++++ cmd/pylonsd/cmd/gadgets.go | 2 +- cmd/pylonsd/cmd/gadgets_test.go | 22 ++++++++++++++++++++++ cmd/pylonsd/main.go | 1 + 5 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 cmd/pylonsd/cmd/dev_parse.go diff --git a/cmd/pylonsd/cmd/dev.go b/cmd/pylonsd/cmd/dev.go index 5ec6044a68..6e5bed8c7b 100644 --- a/cmd/pylonsd/cmd/dev.go +++ b/cmd/pylonsd/cmd/dev.go @@ -15,12 +15,15 @@ import ( "github.com/gogo/protobuf/jsonpb" ) -var Out io.Writer = os.Stdout // modified during testing +var ( + Out io.Writer = os.Stdout // modified during testing + Verbose = false +) // group 1: (whole raw string tokens encapsulated ```like this```) // group 2: (tokens not containing whitespace, separated by whitespace) // group 3: (whatever is in front of the first whitespace) -var gadgetParamParseRegex = regexp.MustCompile(`(\s'''.*''')|(\s.\S*)|(\S*)`) +var gadgetParamParseRegex = regexp.MustCompile(`(\s'''.*?''')|(\s.\S*)|(\S*)`) const ( cookbookExtension = ".plc" @@ -82,7 +85,7 @@ func loadModuleFromPath(modulePath, currentPath string) string { return string(bytes) } -func loadModulesInline(bytes []byte, path string, info os.FileInfo, gadgets *[]Gadget) string { +func LoadModulesInline(bytes []byte, path string, info os.FileInfo, gadgets *[]Gadget) string { lines := strings.Split(string(bytes), "\n") for i, line := range lines { line = strings.TrimSpace(line) @@ -114,7 +117,10 @@ func loadCookbookFromPath(path string, gadgets *[]Gadget) (types.Cookbook, strin info, _ := os.Stat(path) var cb types.Cookbook - json := loadModulesInline(bytes, path, info, gadgets) + json := LoadModulesInline(bytes, path, info, gadgets) + if Verbose { + println(json) + } err := jsonpb.UnmarshalString(json, &cb) return cb, json, err @@ -125,7 +131,10 @@ func loadRecipeFromPath(path string, gadgets *[]Gadget) (types.Recipe, string, e info, _ := os.Stat(path) var rcp types.Recipe - json := loadModulesInline(bytes, path, info, gadgets) + json := LoadModulesInline(bytes, path, info, gadgets) + if Verbose { + println(json) + } err := jsonpb.UnmarshalString(json, &rcp) return rcp, string(bytes), err } diff --git a/cmd/pylonsd/cmd/dev_parse.go b/cmd/pylonsd/cmd/dev_parse.go new file mode 100644 index 0000000000..00c2ab953a --- /dev/null +++ b/cmd/pylonsd/cmd/dev_parse.go @@ -0,0 +1,25 @@ +package cmd + +import ( + "github.com/spf13/cobra" + + "github.com/Pylons-tech/pylons/x/pylons/types" +) + +func DevParse() *cobra.Command { + cmd := &cobra.Command{ + Use: "parse [path]", + Short: "Parses all Pylons recipe or cookbook files in the provided path and processes macros", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + path := args[0] + // This is slightly goofy but it's the fastest/least invasive way to implement this behavior right now. + // We just set a flag to output the assembled JSON and then let the batch handler run with empty callbacks. + // Down the road it'd be nice to have something a little nicer, but this is enough as-is to make debugging more + // manageable. + Verbose = true + ForFiles(path, func(path string, cookbook types.Cookbook) {}, func(path string, recipe types.Recipe) {}) + }, + } + return cmd +} diff --git a/cmd/pylonsd/cmd/gadgets.go b/cmd/pylonsd/cmd/gadgets.go index 09a620de78..f31eb1dff5 100644 --- a/cmd/pylonsd/cmd/gadgets.go +++ b/cmd/pylonsd/cmd/gadgets.go @@ -222,7 +222,7 @@ func parseGadgets(path string, s string) ([]Gadget, error) { func ExpandGadget(gadget *Gadget, params []string) string { str := gadget.json for i := 0; i < gadget.parametersCount; i++ { - str = strings.ReplaceAll(str, "%"+strconv.Itoa(i), strings.TrimSpace(params[i])) + str = strings.ReplaceAll(strings.ReplaceAll(str, "%"+strconv.Itoa(i), strings.TrimSpace(params[i])), "'''", "") // hack - strip the triple quotes more elegantly instead of doing this } return str } diff --git a/cmd/pylonsd/cmd/gadgets_test.go b/cmd/pylonsd/cmd/gadgets_test.go index b64c76c409..ca7daf805a 100644 --- a/cmd/pylonsd/cmd/gadgets_test.go +++ b/cmd/pylonsd/cmd/gadgets_test.go @@ -3,6 +3,7 @@ package cmd import ( "fmt" "os" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -10,6 +11,8 @@ import ( testutil "github.com/Pylons-tech/pylons/testutil/cli" ) +const rcpFilename = "test.rcp" + const pylonsGadgetsLiteral_duplicateName = `#foobar 1 "foo": "%0" #foobar 1 @@ -30,6 +33,10 @@ const pylonsGadgetsLiteral_good = `#go_go_gadget_gadgets 3 "bar": "%1", "%2": "true"` +const gadgetUserLiteral_tripleQuotes = `{ + #go_go_gadget_gadgets '''a triple quoted string''' '''another one''' whatever +}` + func TestGadgets(t *testing.T) { // builtins! @@ -167,4 +174,19 @@ func TestGadgets(t *testing.T) { assert.EqualValues(t, expected, ExpandGadget(gadget, []string{"a", "b", "is_a_gadget"})) os.Remove(gadgetsFilename) }) + + t.Run("Should remove triple quotes from raw string tokens", func(t *testing.T) { + testutil.WriteFixtureAtTestRuntime(gadgetsFilename, pylonsGadgetsLiteral_good) + testutil.WriteFixtureAtTestRuntime(rcpFilename, gadgetUserLiteral_tripleQuotes) + gadgets, err := LoadGadgetsForPath(rcpFilename) + if err != nil { + panic(err) + } + bytes, _ := os.ReadFile(rcpFilename) + info, _ := os.Stat(rcpFilename) + json := LoadModulesInline(bytes, rcpFilename, info, gadgets) + assert.False(t, strings.Contains(json, "'''")) + os.Remove(gadgetsFilename) + os.Remove(rcpFilename) + }) } diff --git a/cmd/pylonsd/main.go b/cmd/pylonsd/main.go index bcb19be325..3c208dca11 100644 --- a/cmd/pylonsd/main.go +++ b/cmd/pylonsd/main.go @@ -21,6 +21,7 @@ func main() { rootCmd.AddCommand(pyloncmd.DevUpdate()) rootCmd.AddCommand(pyloncmd.Completion()) rootCmd.AddCommand(pyloncmd.DevCelCheck()) + rootCmd.AddCommand(pyloncmd.DevParse()) removeLineBreaksInCobraArgs(rootCmd) if err := svrcmd.Execute(rootCmd, "PYLONSD", app.DefaultNodeHome); err != nil {