package console
import (
"embed"
"fmt"
"html/template"
"regexp"
"github.com/pkg/errors"
"github.com/gin-gonic/contrib/renders/multitemplate"
"github.com/hasura/graphql-engine/cli/v2/version"
)
const (
preReleaseVersion = "v1.0-alpha"
unversioned = "unversioned"
versioned = "versioned"
)
type TemplateProvider interface {
// BasePath will return the basepath for the tempalate directory
BasePath() string
// This is the template filename eg: console.html, console2.html
TemplateFilename() string
// DoTemplateExist returns true if an asset exists at pathk
DoTemplateExist(path string) bool
LoadTemplates(path string, templateNames ...string) (multitemplate.Render, error)
// GetTemplateVersion returns the template version tv required to render
// the console html.
GetTemplateVersion(v *version.Version) string
// GetAssetsVersion returns the assets version av to be used in the
// console template. This function is supposed to return the following:
// > input -> output
// > dev-build -> versioned/dev-build
// > v1.0.0-beta.01 -> beta/v1.0
// > v1.0.0-alpha.01 -> alpha/v1.0
// > v1.2.1-rc.03 -> rc/v1.2
// > v1.1.0 -> stable/v1.1
GetAssetsVersion(v *version.Version) string
GetAssetsCDN() string
}
// DefaultTemplateProvider implements the github.com/hasura/graphl-engine/cli/pkg/templates.DefaultTemplateProvider interface
type DefaultTemplateProvider struct {
basePath string
templateFileName string
consoleFS embed.FS
}
func NewDefaultTemplateProvider(basePath, templateFilename string, consoleFS embed.FS) *DefaultTemplateProvider {
return &DefaultTemplateProvider{
basePath: basePath,
templateFileName: templateFilename,
consoleFS: consoleFS,
}
}
func (p *DefaultTemplateProvider) BasePath() string {
return p.basePath
}
func (p *DefaultTemplateProvider) TemplateFilename() string {
return p.templateFileName
}
// DoTemplateExist returns true if an asset exists at pathk
func (p *DefaultTemplateProvider) DoTemplateExist(path string) bool {
_, err := p.consoleFS.ReadFile(path)
return err == nil
}
func (p *DefaultTemplateProvider) LoadTemplates(path string, templateNames ...string) (multitemplate.Render, error) {
r := multitemplate.New()
for _, templateName := range templateNames {
templatePath := path + templateName
templateBytes, err := p.consoleFS.ReadFile(templatePath)
if err != nil {
return nil, errors.Wrap(err, "error reading from file "+templatePath)
}
theTemplate, err := template.New(templateName).Parse(string(templateBytes))
if err != nil {
return nil, errors.Wrap(err, "error creating template"+path+templateName)
}
r.Add(templateName, theTemplate)
}
return r, nil
}
// GetTemplateVersion returns the template version tv required to render
// the console html.
func (p *DefaultTemplateProvider) GetTemplateVersion(v *version.Version) string {
// pre-release builds
if v.Server == "" {
return preReleaseVersion
}
// tagged build
if v.Server != "" {
if v.ServerSemver != nil {
return fmt.Sprintf("v%d.%d", v.ServerSemver.Major(), v.ServerSemver.Minor())
}
}
// untagged version
return unversioned
}
// GetAssetsVersion returns the assets version av to be used in the
// console template. This function is supposed to return the following:
// > input -> output
// > dev-build -> versioned/dev-build
// > v1.0.0-beta.01 -> beta/v1.0
// > v1.0.0-alpha.01 -> alpha/v1.0
// > v1.2.1-rc.03 -> rc/v1.2
// > v1.1.0 -> stable/v1.1
func (p *DefaultTemplateProvider) GetAssetsVersion(v *version.Version) string {
// server has a version
if v.Server != "" {
// version is semver
if v.ServerSemver != nil {
// check for release channels
preRelease := v.ServerSemver.Prerelease()
channel := "stable"
if preRelease != "" {
var re = regexp.MustCompile(`^[a-z]+`)
tag := re.FindString(preRelease)
// cloud and pro will be tagged like v2.0.0-cloud.9
// so, tag will be set as cloud/pro
// then assets should be loaded from stable channel
if tag != "" && tag != "cloud" && tag != "pro" {
channel = tag
}
}
return fmt.Sprintf("channel/%s/v%d.%d", channel, v.ServerSemver.Major(), v.ServerSemver.Minor())
}
// version is not semver
return fmt.Sprintf("%s/%s", versioned, v.Server)
}
// server doesn't have a version - very old server :(
return preReleaseVersion
}
func (p *DefaultTemplateProvider) GetAssetsCDN() string {
return "https://graphql-engine-cdn.hasura.io/console/assets"
}