-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Render files from templates (first step) (#21)
- Loading branch information
1 parent
813a4d9
commit b40e3b4
Showing
14 changed files
with
302 additions
and
53 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package content | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"gopkg.in/yaml.v3" | ||
"strings" | ||
) | ||
|
||
func Unmarshal(v []byte, o interface{}) error { | ||
var err error | ||
|
||
runes := []byte(strings.TrimSpace(string(v))) | ||
if len(runes) == 0 { | ||
return fmt.Errorf("no data in file") | ||
} | ||
|
||
if runes[0] == '{' && runes[len(runes)-1] == '}' { | ||
err = json.Unmarshal(v, o) | ||
} else { | ||
err = yaml.Unmarshal(v, o) | ||
} | ||
|
||
return err | ||
} |
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,123 @@ | ||
package generate | ||
|
||
import ( | ||
"fmt" | ||
"github.com/paloaltonetworks/pan-os-codegen/pkg/properties" | ||
"github.com/paloaltonetworks/pan-os-codegen/pkg/translate" | ||
"io" | ||
"io/fs" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"text/template" | ||
) | ||
|
||
type Creator struct { | ||
GoOutputDir string | ||
TemplatesDir string | ||
Spec *properties.Normalization | ||
} | ||
|
||
func NewCreator(goOutputDir string, templatesDir string, spec *properties.Normalization) *Creator { | ||
return &Creator{ | ||
GoOutputDir: goOutputDir, | ||
TemplatesDir: templatesDir, | ||
Spec: spec, | ||
} | ||
} | ||
|
||
func (c *Creator) RenderTemplate() error { | ||
templates := make([]string, 0, 100) | ||
templates, err := c.listOfTemplates(templates) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, templateName := range templates { | ||
filePath := c.createFullFilePath(c.GoOutputDir, c.Spec, templateName) | ||
fmt.Printf("Create file %s\n", filePath) | ||
|
||
if err := c.makeAllDirs(filePath, err); err != nil { | ||
return err | ||
} | ||
|
||
outputFile, err := c.createFile(filePath) | ||
if err != nil { | ||
return err | ||
} | ||
defer func(outputFile *os.File) { | ||
err := outputFile.Close() | ||
if err != nil { | ||
|
||
} | ||
}(outputFile) | ||
|
||
tmpl, err := c.parseTemplate(templateName) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = c.generateOutputFileFromTemplate(tmpl, outputFile, c.Spec) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (c *Creator) generateOutputFileFromTemplate(tmpl *template.Template, output io.Writer, spec *properties.Normalization) error { | ||
if err := tmpl.Execute(output, spec); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (c *Creator) parseTemplate(templateName string) (*template.Template, error) { | ||
templatePath := fmt.Sprintf("%s/%s", c.TemplatesDir, templateName) | ||
funcMap := template.FuncMap{ | ||
"packageName": translate.PackageName, | ||
} | ||
tmpl, err := template.New(templateName).Funcs(funcMap).ParseFiles(templatePath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return tmpl, nil | ||
} | ||
|
||
func (c *Creator) createFullFilePath(goOutputDir string, spec *properties.Normalization, templateName string) string { | ||
return fmt.Sprintf("%s/%s/%s.go", goOutputDir, strings.Join(spec.GoSdkPath, "/"), strings.Split(templateName, ".")[0]) | ||
} | ||
|
||
func (c *Creator) listOfTemplates(files []string) ([]string, error) { | ||
err := filepath.WalkDir(c.TemplatesDir, func(path string, entry fs.DirEntry, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if strings.HasSuffix(entry.Name(), ".tmpl") { | ||
files = append(files, filepath.Base(path)) | ||
} | ||
|
||
return nil | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return files, nil | ||
} | ||
|
||
func (c *Creator) createFile(filePath string) (*os.File, error) { | ||
outputFile, err := os.Create(filePath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return outputFile, nil | ||
} | ||
|
||
func (c *Creator) makeAllDirs(filePath string, err error) error { | ||
dirPath := filepath.Dir(filePath) | ||
if err = os.MkdirAll(dirPath, os.ModePerm); err != nil { | ||
return err | ||
} | ||
return 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,68 @@ | ||
package generate | ||
|
||
import ( | ||
"bytes" | ||
"github.com/paloaltonetworks/pan-os-codegen/pkg/properties" | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestCreateFullFilePath(t *testing.T) { | ||
// given | ||
spec := properties.Normalization{ | ||
GoSdkPath: []string{"go"}, | ||
} | ||
generator := NewCreator("test", "../../templates/sdk", &spec) | ||
|
||
// when | ||
fullFilePath := generator.createFullFilePath("output", &spec, "template.tmpl") | ||
|
||
// then | ||
assert.NotNil(t, fullFilePath) | ||
assert.Equal(t, "output/go/template.go", fullFilePath) | ||
} | ||
|
||
// NOTE - unit tests should only touch code inside package, do not reference external resources. | ||
// Nevertheless, below tests ARE REFERENCING to text templates, because template ARE NOT EMBEDDED into Go files. | ||
// Technically we could embed them, but then: | ||
// 1 - we are losing clarity of the code, | ||
// 2 - we are mixing Golang with templates expressions. | ||
// Testing generator is crucial, so below tests we can br treated more as integration tests, not unit one. | ||
|
||
func TestListOfTemplates(t *testing.T) { | ||
// given | ||
spec := properties.Normalization{ | ||
GoSdkPath: []string{"go"}, | ||
} | ||
generator := NewCreator("test", "../../templates/sdk", &spec) | ||
|
||
// when | ||
var templates []string | ||
templates, _ = generator.listOfTemplates(templates) | ||
|
||
// then | ||
assert.Equal(t, 4, len(templates)) | ||
} | ||
|
||
func TestParseTemplate(t *testing.T) { | ||
// given | ||
spec := properties.Normalization{ | ||
GoSdkPath: []string{"object", "address"}, | ||
} | ||
generator := NewCreator("test", "../../templates/sdk", &spec) | ||
expectedFileContent := `package address | ||
type Specifier func(Entry) (any, error) | ||
type Normalizer interface { | ||
Normalize() ([]Entry, error) | ||
}` | ||
|
||
// when | ||
template, _ := generator.parseTemplate("interfaces.tmpl") | ||
var output bytes.Buffer | ||
_ = generator.generateOutputFileFromTemplate(template, &output, generator.Spec) | ||
|
||
// then | ||
assert.Equal(t, expectedFileContent, output.String()) | ||
} |
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
Oops, something went wrong.