mirror of https://github.com/knative/func.git
				
				
				
			
		
			
				
	
	
		
			95 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			95 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
| package scaffolding
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"go/ast"
 | |
| 	"go/parser"
 | |
| 	"go/token"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // detector of method signatures.  Each instance is for a given runtime.
 | |
| type detector interface {
 | |
| 	Detect(dir string) (static, instanced bool, err error)
 | |
| }
 | |
| 
 | |
| // newDetector returns a deector instance for the given runtime.
 | |
| func newDetector(runtime string) (detector, error) {
 | |
| 	switch runtime {
 | |
| 	case "go":
 | |
| 		return &goDetector{}, nil
 | |
| 	case "python":
 | |
| 		return &pythonDetector{}, nil
 | |
| 	case "rust":
 | |
| 		return nil, ErrDetectorNotImplemented{runtime}
 | |
| 	case "node":
 | |
| 		return nil, ErrDetectorNotImplemented{runtime}
 | |
| 	case "typescript":
 | |
| 		return nil, ErrDetectorNotImplemented{runtime}
 | |
| 	case "quarkus":
 | |
| 		return nil, ErrDetectorNotImplemented{runtime}
 | |
| 	case "java":
 | |
| 		return nil, ErrDetectorNotImplemented{runtime}
 | |
| 	default:
 | |
| 		return nil, ErrRuntimeNotRecognized{runtime}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // GO
 | |
| 
 | |
| type goDetector struct{}
 | |
| 
 | |
| func (d goDetector) Detect(dir string) (static, instanced bool, err error) {
 | |
| 	files, err := os.ReadDir(dir)
 | |
| 	if err != nil {
 | |
| 		return static, instanced, fmt.Errorf("signature detector encountered an error when scanning the function's source code. %w", err)
 | |
| 	}
 | |
| 	for _, file := range files {
 | |
| 		filename := filepath.Join(dir, file.Name())
 | |
| 		if file.IsDir() || !strings.HasSuffix(filename, ".go") {
 | |
| 			continue
 | |
| 		}
 | |
| 		if d.hasFunctionDeclaration(filename, "New") {
 | |
| 			instanced = true
 | |
| 		}
 | |
| 		if d.hasFunctionDeclaration(filename, "Handle") {
 | |
| 			static = true
 | |
| 		}
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (d goDetector) hasFunctionDeclaration(filename, function string) bool {
 | |
| 	astFile, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.SkipObjectResolution)
 | |
| 	if err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	for _, decl := range astFile.Decls {
 | |
| 		if funcDecl, ok := decl.(*ast.FuncDecl); ok {
 | |
| 			// Name matches and it has no reciver.  I.e. a package level function
 | |
| 			if funcDecl.Name.Name == function && funcDecl.Recv == nil {
 | |
| 				return true
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // PYTHON
 | |
| 
 | |
| type pythonDetector struct{}
 | |
| 
 | |
| func (d pythonDetector) Detect(dir string) (static, instanced bool, err error) {
 | |
| 	// The python middleware handles detecting if the Function has the static
 | |
| 	// and/or instanced method signatures, so we can presume the suggested
 | |
| 	// default of "instanced" here.
 | |
| 	// Ideally we'd refactor this to support in-code the idea of "detection
 | |
| 	// not necessary for this runtime".
 | |
| 	instanced = true
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // TODO: Other Detectors
 |