From e2f5c66b1c52fa36c19256daedf09da1d041866b Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 14 Jul 2023 14:26:28 +0200 Subject: [PATCH] Remove custom template logic This commit removes custom template logic in the entire distillery codebase. --- .../{create-repo.ttl => create-repo.tpl} | 9 +- .../dis/component/triplestore/provision.go | 29 ++- pkg/unpack/template.go | 196 ------------------ 3 files changed, 24 insertions(+), 210 deletions(-) rename internal/dis/component/triplestore/{create-repo.ttl => create-repo.tpl} (88%) delete mode 100644 pkg/unpack/template.go diff --git a/internal/dis/component/triplestore/create-repo.ttl b/internal/dis/component/triplestore/create-repo.tpl similarity index 88% rename from internal/dis/component/triplestore/create-repo.ttl rename to internal/dis/component/triplestore/create-repo.tpl index 410013e..12f17e5 100644 --- a/internal/dis/component/triplestore/create-repo.ttl +++ b/internal/dis/component/triplestore/create-repo.tpl @@ -1,6 +1,5 @@ # This file is used to initialize a new GraphDB repository. -# In this file the variables ${GRAPHDB_REPO} and ${INSTANCE_DOMAIN} will be replaced. -# All other variables will be left untouched. +# It is filled at runtime. @prefix rdfs: . @prefix rep: . @@ -9,8 +8,8 @@ @prefix owlim: . [] a rep:Repository ; - rep:repositoryID "${GRAPHDB_REPO}" ; - rdfs:label "${INSTANCE_DOMAIN}" ; + rep:repositoryID "{{ .RepositoryID }}" ; + rdfs:label "{{ .Label }}" ; rep:repositoryImpl [ rep:repositoryType "graphdb:SailRepository" ; sr:sailImpl [ @@ -18,7 +17,7 @@ owlim:owlim-license "" ; - owlim:base-URL "http://${INSTANCE_DOMAIN}/" ; + owlim:base-URL "{{ .BaseURL }}" ; owlim:defaultNS "" ; owlim:entity-index-size "10000000" ; owlim:entity-id-size "32" ; diff --git a/internal/dis/component/triplestore/provision.go b/internal/dis/component/triplestore/provision.go index 3066393..f9d42d2 100644 --- a/internal/dis/component/triplestore/provision.go +++ b/internal/dis/component/triplestore/provision.go @@ -5,11 +5,11 @@ import ( "context" "errors" "net/http" + "text/template" _ "embed" "github.com/FAU-CDI/wisski-distillery/internal/models" - "github.com/FAU-CDI/wisski-distillery/pkg/unpack" "github.com/tkw1536/goprogram/exit" ) @@ -18,8 +18,20 @@ var errTripleStoreFailedRepository = exit.Error{ ExitCode: exit.ExitGeneric, } -//go:embed create-repo.ttl -var createRepoTTL []byte +//go:embed create-repo.tpl +var createRepoTpl string + +// Template for creating repositories. +// +// NOTE(twiesing): The template is not aware of SparQL syntax, thus this template is very unsafe. +// And should only be used with KNOWN GOOD input. +var creteRepoTemplate = template.Must(template.New("create-repo.tpl").Parse(createRepoTpl)) + +type createRepoContext struct { + RepositoryID string + Label string + BaseURL string +} func (ts *Triplestore) Provision(ctx context.Context, instance models.Instance, domain string) error { return ts.CreateRepository(ctx, instance.GraphDBRepository, domain, instance.GraphDBUsername, instance.GraphDBPassword) @@ -39,12 +51,11 @@ func (ts *Triplestore) CreateRepository(ctx context.Context, name, domain, user, // prepare the create repo request var createRepo bytes.Buffer - - err := unpack.WriteTemplate(&createRepo, map[string]string{ - "GRAPHDB_REPO": name, - "INSTANCE_DOMAIN": domain, - }, bytes.NewReader(createRepoTTL)) - if err != nil { + if err := creteRepoTemplate.Execute(&createRepo, createRepoContext{ + RepositoryID: name, + Label: domain, + BaseURL: "http://" + domain + "/", + }); err != nil { return err } diff --git a/pkg/unpack/template.go b/pkg/unpack/template.go deleted file mode 100644 index ae4dba4..0000000 --- a/pkg/unpack/template.go +++ /dev/null @@ -1,196 +0,0 @@ -// Package unpack unpacks files and templates to a target directory. -package unpack - -import ( - "bufio" - "fmt" - "io" - "strings" - - "golang.org/x/exp/maps" - "golang.org/x/exp/slices" -) - -// ts represents state of the template parser -type ts int - -const ( - tsGobble ts = iota // gobble into dst - tsSawDollar // saw a '$' - tsGobbleVar // gobble into var -) - -// MissingTemplateKeyError indicates [WriteTemplate] found missing keys in the context -type MissingTemplateKeyError struct { - Keys []string -} - -func (mtke MissingTemplateKeyError) Error() string { - return fmt.Sprintf("missing template keys from context: %v", mtke.Keys) -} - -// UnusuedTemplateKeyError indicates [WriteTemplate] found unusued keys in the context -type UnusuedTemplateKeyError struct { - Keys []string -} - -func (utke UnusuedTemplateKeyError) Error() string { - return fmt.Sprintf("unused template keys from context: %v", utke.Keys) -} - -// WriteTemplate writes the template defined by src with the given context into reader. -// -// To run the template, variables of the form ${NAME} are replaced with their corresponding value from the context. -// -// If an underlying read or write fails, it is returned as is. -// Missing template keys return a [MissingTemplateKeyError], but are replaced with the empty string. -// Unused template keys return a [UnusuedTemplateKeyError], but are replaced with the empty string. -// -// Reader / Writer errors are always returned first; next missing template keys, and finally unused template keys. -func WriteTemplate(dst io.Writer, context map[string]string, src io.Reader) error { - - // We keep track of contect keys that have not been used. - // - // We first fill the map with all the keys from the context. - // Then when we use a key, we delete it from the map. - // If there are any keys left at the end of the replacement, that is an error. - unusedKeys := make(map[string]struct{}, len(context)) - for key := range context { - unusedKeys[key] = struct{}{} - } - - // When we encounter a missing key, put it into this map. - // This is so that we can build an error message below. - missingKeys := make(map[string]struct{}, 0) - - // We use a new bufio reader to read data from the input. - // This is a cheap trick to get a ReadRune() method. - reader := bufio.NewReader(src) - - // - // MAIN PARSING LOOP - // - - // start out in gobble mode! - mode := tsGobble - - // keep track of variable names - var varB strings.Builder - -parseloop: - for { - r, _, err := reader.ReadRune() - switch { - case err == io.EOF: - // finished parsing the source - break parseloop - case err != nil: - // the reader broke - return err - - case mode == tsGobble && r == '$': - // saw a '$' in gobble mode - mode = tsSawDollar - case mode == tsGobble: - // normal gobbleing - // => pass it through - if _, err := dst.Write([]byte{byte(r)}); err != nil { - return err - } - - case mode == tsSawDollar && r == '{': - // saw '{', following the '$' - // => read everything else into the buffer - mode = tsGobbleVar - case mode == tsSawDollar && r == '$': - // saw a '$' following the '$' - // => write the first '$', and handle the case $${stuff} - if _, err := dst.Write([]byte("$")); err != nil { - return err - } - case mode == tsSawDollar: - // saw anything else following the '$' - // => write both back and switch back to gobble mode - if _, err := dst.Write([]byte{byte('$'), byte(r)}); err != nil { - return err - } - mode = tsGobble - - case mode == tsGobbleVar && r != '}': - // saw anything except for closing bracket - // => keep it in the buffer - if _, err := varB.WriteRune(r); err != nil { - return err - } - - case mode == tsGobbleVar: - // saw a closing '}' inside tsGobbleVar mode - // => use the variable - - name := varB.String() - - // get the variable from the context - value, ok := context[name] - - delete(unusedKeys, name) // mark the variable as used! - if !ok { - // store unusued variables - missingKeys[name] = struct{}{} - value = "" - } - - // write the replacement into the string - if _, err := io.WriteString(dst, value); err != nil { - return err - } - - // reset the builder and go back into normal mode - varB.Reset() - mode = tsGobble - } - } - - // - // CLEANUP UNUSUED INPUT - // - - switch mode { - case tsSawDollar: - // we had a '$', but no '{' - // => write the trailing '$' into dest - if _, err := dst.Write([]byte("$")); err != nil { - return err - } - case tsGobbleVar: - // we had a "${", followed by somthing unclosed - // => write everything back into the dst - if _, err := dst.Write([]byte("${")); err != nil { - return err - } - if _, err := io.WriteString(dst, varB.String()); err != nil { - return err - } - } - - // Check if there were missing template keys. - // If so, we sort them and return an appropriate error. - if len(missingKeys) != 0 { - keys := maps.Keys(missingKeys) - slices.Sort(keys) - return MissingTemplateKeyError{ - Keys: keys, - } - } - - // Check if there were unused template keys. - // If so, we sort them and return an appropriate error. - if len(unusedKeys) != 0 { - keys := maps.Keys(unusedKeys) - slices.Sort(keys) - return UnusuedTemplateKeyError{ - Keys: keys, - } - } - - return nil -}