代码拉取完成,页面将自动刷新
package template
import (
"context"
"fmt"
"gitee.com/anesec/chameleon/pkg/template/expr"
"gopkg.in/yaml.v3"
"io"
"net/http"
"path/filepath"
"strings"
)
type Template struct {
Name string `yaml:"template"`
Brief string `yaml:"brief"`
Author string `yaml:"author"`
Category string `yaml:"category"`
Annotations map[string]string `yaml:"annotations"`
Service *Service `yaml:"service"`
Frameworks []*Framework `yaml:"frameworks"`
}
func (template *Template) compile(reader io.Reader) error {
if err := yaml.NewDecoder(reader).Decode(template); err != nil {
return err
}
if template.Service != nil {
template.Service.manifest = template
return template.Service.compile()
} else if template.Frameworks != nil {
for _, framework := range template.Frameworks {
framework.manifest = template
if err := framework.compile(); err != nil {
return err
}
}
return nil
}
return fmt.Errorf("invalid template")
}
func (template *Template) eval(ctx context.Context, source expr.Source, kind Kind) bool {
if (kind == KindApplication || kind == KindUnknown) && template.Service != nil {
return template.Service.eval(ctx, source)
} else if (kind == KindFramework || kind == KindUnknown) && template.Frameworks != nil {
for _, framework := range template.Frameworks {
framework.eval(ctx, source)
}
}
return false
}
type templates []*Template
func (t templates) Len() int {
return len(t)
}
func (t templates) Less(i, j int) bool {
if t[i].Category == "ai" {
return true
} else if t[j].Category == "ai" {
return false
}
return t[i].Name < t[j].Name
}
func (t templates) Swap(i, j int) {
t[i], t[j] = t[j], t[i]
}
type httpRequest struct {
Urls []string `yaml:"urls"`
Method string `yaml:"method"`
Code int `yaml:"code"`
LimitBytes int `yaml:"limit_bytes"`
}
type Metadata struct {
Name string `yaml:"name"`
Value string `yaml:"value"`
Expr string `yaml:"expr"`
Exec string `yaml:"exec"`
Request *httpRequest `yaml:"http"`
Defaults []string `yaml:"defaults"` // defaults absolute file paths
Bases []string `yaml:"bases"` // defaults absolute base file paths, without filename
Files []string `yaml:"files"` // file paths, related to Bases or captured config path
appName string
expr expr.Expr
}
func (meta *Metadata) compile(app string) (err error) {
if _, ok := builtinAppConfigParsers[strings.ToLower(app)]; ok {
meta.appName = strings.ToLower(app)
}
if meta.Request != nil {
if len(meta.Request.Urls) == 0 {
return fmt.Errorf("invalid http request, no urls")
}
if meta.Request.Method != "" {
meta.Request.Method = strings.ToUpper(meta.Request.Method)
} else {
meta.Request.Method = http.MethodGet
}
if meta.Request.Code == 0 {
meta.Request.Code = http.StatusOK
}
switch meta.Request.Method {
case http.MethodGet, http.MethodPost, http.MethodPut, http.MethodHead:
default:
return fmt.Errorf("unsupported http method: %s", meta.Request.Method)
}
}
if meta.Expr != "" {
meta.expr, err = expr.Compile(meta.Expr)
}
return
}
func (meta *Metadata) eval(ctx context.Context, source expr.Source) bool {
if meta.Exec != "" {
cmd := &commandSourceWrapper{Source: source, exec: meta.Exec}
defer cmd.finalize()
source = cmd
}
if meta.Request != nil && len(meta.Request.Urls) > 0 {
source = &httpSourceWrapper{Source: source, request: meta.Request}
}
if meta.expr != nil {
if meta.expr.Eval(ctx, source) {
return true
}
} else if meta.Exec != "" {
value, ok := source.Provide("exec.output").(string)
if !ok || value == "" {
return false
}
source.Capture(meta.Name, value)
return true
} else if meta.Request != nil {
value, ok := source.Provide("http.body").(string)
if !ok || value == "" {
return false
}
source.Capture(meta.Name, value)
return true
}
if meta.Value != "" {
source.Capture(meta.Name, meta.Value)
return true
}
for i := range meta.Defaults {
source.Capture(meta.Name, meta.Defaults[i])
return true
}
if len(meta.Bases) > 0 && len(meta.Files) > 0 {
for _, basis := range meta.Bases {
for _, file := range meta.Files {
source.Capture(meta.Name, filepath.Join(basis, file))
}
}
return true
}
return false
}
type WebApp struct {
Name string `yaml:"name"`
Expr string `yaml:"expr"`
Exec string `yaml:"exec"`
Version *Metadata `yaml:"version"`
expr expr.Expr
}
func (webapp *WebApp) compile() (err error) {
if webapp.expr, err = expr.Compile(webapp.Expr); err != nil {
return
}
if webapp.Version != nil {
err = webapp.Version.compile("")
}
return
}
func (webapp *WebApp) eval(ctx context.Context, source expr.Source) bool {
if webapp.expr == nil {
return false
}
source = &webappSourceWrapper{Source: source}
if webapp.Exec != "" {
cmd := &commandSourceWrapper{Source: source, exec: webapp.Exec}
defer cmd.finalize()
source = cmd
}
if !webapp.expr.Eval(ctx, source) {
return false
}
source.Capture("webapp.name", webapp.Name)
if webapp.Version != nil {
webapp.Version.eval(ctx, source)
}
return true
}
type Service struct {
Expr string `yaml:"expr"`
Exec string `yaml:"exec"`
Keyword string `yaml:"keyword"`
Metadata []*Metadata `yaml:"metadata"`
Web []*WebApp `yaml:"webapp"`
manifest *Template
expr expr.Expr
}
func (svc *Service) compile() (err error) {
if svc.expr, err = expr.Compile(svc.Expr); err != nil {
return
}
for index := range svc.Metadata {
if err = svc.Metadata[index].compile(svc.manifest.Name); err != nil {
return
}
}
for _, webapp := range svc.Web {
if err = webapp.compile(); err != nil {
return
}
}
return
}
func (svc *Service) eval(ctx context.Context, source expr.Source) bool {
if svc.expr == nil {
return false
}
wrapper := &serviceSourceWrapper{Source: source, keyword: svc.Keyword}
source = wrapper
if svc.Exec != "" && strings.Index(svc.Expr, "exec.output") > 0 {
cmd := &commandSourceWrapper{Source: source, exec: svc.Exec}
defer cmd.finalize()
if !svc.expr.Eval(ctx, cmd) {
return false
}
} else if !svc.expr.Eval(ctx, source) {
return false
}
source.Capture("service.name", svc.manifest.Name)
source.Capture("service.category", svc.manifest.Category)
var config *configSourceWrapper
defer func() {
if config != nil {
config.finalize()
}
}()
for _, metadata := range svc.Metadata {
// skip version capture if already captured by previous expression
if metadata.Name == "version" && wrapper.captured("service.version") {
continue
}
if metadata.Name == "config" && config == nil {
config = &configSourceWrapper{Source: source, appName: metadata.appName, bases: metadata.Bases, files: metadata.Files}
source = config
}
metadata.eval(ctx, source)
}
for _, webapp := range svc.Web {
webapp.eval(ctx, source)
}
return true
}
type Framework struct {
Name string `yaml:"name"`
Maintainer string `yaml:"maintainer"`
License string `yaml:"license"`
Category string `yaml:"category"`
Expr string `yaml:"expr"`
manifest *Template
expr expr.Expr
}
func (framework *Framework) compile() (err error) {
if framework.Category == "" {
framework.Category = framework.manifest.Category
}
framework.expr, err = expr.Compile(framework.Expr, expr.CaptureValue("framework.version"))
return
}
func (framework *Framework) eval(ctx context.Context, source expr.Source) bool {
source = &frameworkSourceWrapper{Source: source}
if framework.expr == nil || !framework.expr.Eval(ctx, source) {
return false
}
source.Capture("framework.name", framework.Name)
source.Capture("framework.category", framework.manifest.Category)
source.Capture("framework.maintainer", framework.Maintainer)
source.Capture("framework.license", framework.License)
return true
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。