Skip to content

Commit

Permalink
Add modeline, and parser for it
Browse files Browse the repository at this point in the history
  • Loading branch information
kvaps committed May 4, 2024
1 parent 6e8fdcd commit 5903bd0
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 1 deletion.
33 changes: 32 additions & 1 deletion pkg/commands/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package commands

import (
"context"
"encoding/json"
"fmt"

"github.com/aenix-io/talm/pkg/engine"
Expand Down Expand Up @@ -72,8 +73,13 @@ func template(args []string) func(ctx context.Context, c *client.Client) error {
return fmt.Errorf("failed to render templates: %w", err)
}

modeline, err := generateModeline(args)
if err != nil {
return fmt.Errorf("failed generate modeline: %w", err)
}

// Print the result to the standard output
fmt.Println(string(result))
fmt.Printf("%s\n%s", modeline, string(result))

return nil
}
Expand Down Expand Up @@ -120,3 +126,28 @@ func init() {

addCommand(templateCmd)
}

// generateModeline creates a modeline string using JSON formatting for values
func generateModeline(templates []string) (string, error) {
// Convert Nodes to JSON
nodesJSON, err := json.Marshal(GlobalArgs.Nodes)
if err != nil {
return "", fmt.Errorf("failed to marshal nodes: %v", err)
}

// Convert Endpoints to JSON
endpointsJSON, err := json.Marshal(GlobalArgs.Endpoints)
if err != nil {
return "", fmt.Errorf("failed to marshal endpoints: %v", err)
}

// Convert Templates to JSON
templatesJSON, err := json.Marshal(templates)
if err != nil {
return "", fmt.Errorf("failed to marshal templates: %v", err)
}

// Form the final modeline string
modeline := fmt.Sprintf(`# talm: nodes=%s, endpoints=%s, templates=%s`, string(nodesJSON), string(endpointsJSON), string(templatesJSON))
return modeline, nil
}
49 changes: 49 additions & 0 deletions pkg/modeline/modeline.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package modeline

import (
"encoding/json"
"fmt"
"strings"
)

// Config structure for storing settings from modeline
type Config struct {
Nodes []string
Endpoints []string
Templates []string
}

// ParseModeline parses a modeline string and populates the Config structure
func ParseModeline(line string) (*Config, error) {
config := &Config{}
trimLine := strings.TrimSpace(line)
prefix := "# talm: "
if strings.HasPrefix(trimLine, prefix) {
content := strings.TrimPrefix(trimLine, prefix)
parts := strings.Split(content, ", ")
for _, part := range parts {
keyVal := strings.SplitN(strings.TrimSpace(part), "=", 2)
if len(keyVal) != 2 {
return nil, fmt.Errorf("invalid format of modeline part: %s", part)
}
key := keyVal[0]
val := keyVal[1]
var arr []string
if err := json.Unmarshal([]byte(val), &arr); err != nil {
return nil, fmt.Errorf("error parsing JSON array for key %s, value %s, error: %v", key, val, err)
}
// Assign values to Config fields based on known keys
switch key {
case "nodes":
config.Nodes = arr
case "endpoints":
config.Endpoints = arr
case "templates":
config.Templates = arr
// Ignore unknown keys
}
}
return config, nil
}
return nil, fmt.Errorf("modeline prefix not found")
}
48 changes: 48 additions & 0 deletions pkg/modeline/modeline_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package modeline

import (
"reflect"
"testing"
)

func TestParseModeline(t *testing.T) {
testCases := []struct {
name string
line string
want *Config
wantErr bool
}{
{
name: "valid modeline with all known keys",
line: `# talm: nodes=["192.168.100.2"], endpoints=["1.2.3.4","127.0.0.1","192.168.100.2"], templates=["templates/controlplane.yaml","templates/worker.yaml"]`,
want: &Config{
Nodes: []string{"192.168.100.2"},
Endpoints: []string{"1.2.3.4", "127.0.0.1", "192.168.100.2"},
Templates: []string{"templates/controlplane.yaml", "templates/worker.yaml"},
},
wantErr: false,
},
{
name: "modeline with unknown key",
line: `# talm: nodes=["192.168.100.2"], endpoints=["1.2.3.4","127.0.0.1","192.168.100.2"], unknown=["value"]`,
want: &Config{
Nodes: []string{"192.168.100.2"},
Endpoints: []string{"1.2.3.4", "127.0.0.1", "192.168.100.2"},
},
wantErr: false,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got, err := ParseModeline(tc.line)
if (err != nil) != tc.wantErr {
t.Errorf("parseModeline() error = %v, wantErr %v", err, tc.wantErr)
return
}
if !tc.wantErr && !reflect.DeepEqual(got, tc.want) {
t.Errorf("parseModeline() got = %v, want %v", got, tc.want)
}
})
}
}

0 comments on commit 5903bd0

Please sign in to comment.