implement 'AICRA' command | system to parse config, set defaults, infer map of sources from a folder, etc
This commit is contained in:
parent
c51281c731
commit
b6e19c255b
|
@ -6,65 +6,38 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Builds types as plugins (.so)
|
// compile compiles the 'source' file into the 'build' path
|
||||||
// from the sources in the @in folder
|
func compile(source, build string) {
|
||||||
// recursively and generate .so files
|
|
||||||
// into the @out folder with the same structure
|
|
||||||
func compile(in string, out string) error {
|
|
||||||
|
|
||||||
/* (1) Create build folder */
|
// 2. Create folder
|
||||||
clifmt.Align(" . create output folder")
|
clifmt.Align(" + create output folder")
|
||||||
err := os.MkdirAll(out, os.ModePerm)
|
err := os.MkdirAll(filepath.Dir(build), os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
fmt.Printf("fail\n")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("ok\n")
|
fmt.Printf("ok\n")
|
||||||
|
|
||||||
/* (2) List recursively */
|
// 3. Compile
|
||||||
types := []string{}
|
clifmt.Align(" + compile")
|
||||||
err = filepath.Walk(in, func(path string, f os.FileInfo, err error) error {
|
|
||||||
if strings.HasSuffix(path, "/main.go") {
|
|
||||||
types = append(types, filepath.Base(filepath.Dir(path)))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Print files */
|
|
||||||
for _, name := range types {
|
|
||||||
|
|
||||||
// 1. process output file name
|
|
||||||
infile := filepath.Join(in, name, "main.go")
|
|
||||||
outfile := filepath.Join(out, fmt.Sprintf("%s.so", name))
|
|
||||||
|
|
||||||
clifmt.Align(fmt.Sprintf(" . compile %s", clifmt.Color(33, name)))
|
|
||||||
|
|
||||||
// 2. compile
|
|
||||||
stdout, err := exec.Command("go",
|
stdout, err := exec.Command("go",
|
||||||
"build", "-buildmode=plugin",
|
"build", "-buildmode=plugin",
|
||||||
"-o", outfile,
|
"-o", build,
|
||||||
infile,
|
source,
|
||||||
).Output()
|
).Output()
|
||||||
|
|
||||||
// 3. success
|
// 4. success
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("ok\n")
|
fmt.Printf("ok\n")
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. debug error
|
// 5. debug error
|
||||||
fmt.Printf("error\n")
|
fmt.Printf("error\n")
|
||||||
if len(stdout) > 0 {
|
if len(stdout) > 0 {
|
||||||
fmt.Printf("%s\n%s\n%s\n", clifmt.Color(31, "-=-"), stdout, clifmt.Color(31, "-=-"))
|
fmt.Printf("%s\n%s\n%s\n", clifmt.Color(31, "-=-"), stdout, clifmt.Color(31, "-=-"))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Returns an absolute path from the @path variable if already absolute
|
|
||||||
// if @path is relative, it is processed relative to the @base directory
|
|
||||||
func getAbsPath(base string, path string) (string, error) {
|
|
||||||
|
|
||||||
// already absolute
|
|
||||||
if filepath.IsAbs(path) {
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// relative: join from @base dir
|
|
||||||
return filepath.Abs(filepath.Join(base, path))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns whether a directory exists for the path @path
|
|
||||||
func dirExists(path string) bool {
|
|
||||||
stat, err := os.Stat(path)
|
|
||||||
return err == nil && stat.IsDir()
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.xdrm.io/go/aicra/internal/clifmt"
|
"git.xdrm.io/go/aicra/internal/clifmt"
|
||||||
|
"git.xdrm.io/go/aicra/internal/meta"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
@ -11,170 +11,84 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
starttime := time.Now().UnixNano()
|
starttime := time.Now()
|
||||||
|
|
||||||
/* (1) Flags
|
/* 1. Load config */
|
||||||
---------------------------------------------------------*/
|
schema, err := meta.Parse("./aicra.json")
|
||||||
/* (1) controller path */
|
|
||||||
ctlPathFlag := flag.String("c", "controller", "Path to controllers' directory")
|
|
||||||
|
|
||||||
/* (2) types path */
|
|
||||||
typPathFlag := flag.String("t", "type", "Path to custom types' directory")
|
|
||||||
|
|
||||||
/* (3) middleware path */
|
|
||||||
midPathFlag := flag.String("m", "middleware", "Path to middlewares' directory")
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
/* (3) Get last arg: project path */
|
|
||||||
if len(flag.Args()) < 1 {
|
|
||||||
fmt.Printf("%s\n\n", clifmt.Warn("missing argument"))
|
|
||||||
fmt.Printf("You must provide the project folder as the last argument\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var projectPathFlag = flag.Arg(0)
|
|
||||||
compileTypes := true
|
|
||||||
compileControllers := true
|
|
||||||
compileMiddlewares := true
|
|
||||||
|
|
||||||
/* (2) Get absolute paths
|
|
||||||
---------------------------------------------------------*/
|
|
||||||
/* (1) Get absolute project path */
|
|
||||||
projectPath, err := filepath.Abs(projectPathFlag)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("invalid argument: project path\n")
|
fmt.Printf("aicra.json: %s\n", err)
|
||||||
return
|
|
||||||
}
|
|
||||||
/* (2) Get absolute controllers' path */
|
|
||||||
cPath, err := getAbsPath(projectPath, *ctlPathFlag)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("invalid argument: controllers' path\n")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) Get absolute types' path */
|
/* 2. End if nothing to compile */
|
||||||
tPath, err := getAbsPath(projectPath, *typPathFlag)
|
if !schema.Driver.Compiled() {
|
||||||
if err != nil {
|
fmt.Printf("\n[ %s | %s ] nothing to compile\n",
|
||||||
fmt.Printf("invalid argument: types' path\n")
|
clifmt.Color(32, "finished"),
|
||||||
|
time.Now().Sub(starttime),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (4) Get absolute middlewares' path */
|
/* Compile
|
||||||
mPath, err := getAbsPath(projectPath, *midPathFlag)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("invalid argument: middlwares' path\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// default types folder
|
|
||||||
dtPath := filepath.Join(os.Getenv("GOPATH"), "src/git.xdrm.io/go/aicra/internal/checker/default")
|
|
||||||
|
|
||||||
/* (3) Check path are existing dirs
|
|
||||||
---------------------------------------------------------*/
|
|
||||||
clifmt.Title("file check")
|
|
||||||
|
|
||||||
/* (1) Project path */
|
|
||||||
clifmt.Align(" . project root")
|
|
||||||
if !dirExists(projectPath) {
|
|
||||||
fmt.Printf("invalid\n\n")
|
|
||||||
fmt.Printf("%s invalid project folder - %s\n\n", clifmt.Warn(), clifmt.Color(36, projectPath))
|
|
||||||
fmt.Printf("You must specify an existing directory path\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Printf("ok\n")
|
|
||||||
|
|
||||||
/* (2) Controllers path */
|
|
||||||
clifmt.Align(" . controllers")
|
|
||||||
if !dirExists(cPath) {
|
|
||||||
compileControllers = false
|
|
||||||
fmt.Printf("missing\n")
|
|
||||||
} else {
|
|
||||||
fmt.Printf("ok\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Middlewares path */
|
|
||||||
clifmt.Align(" . middlewares")
|
|
||||||
if !dirExists(mPath) {
|
|
||||||
compileMiddlewares = false
|
|
||||||
fmt.Printf("missing\n")
|
|
||||||
} else {
|
|
||||||
fmt.Printf("ok\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (4) Default types path */
|
|
||||||
clifmt.Align(" . default types")
|
|
||||||
if !dirExists(dtPath) {
|
|
||||||
fmt.Printf("missing\n")
|
|
||||||
compileTypes = false
|
|
||||||
|
|
||||||
} else {
|
|
||||||
fmt.Printf("ok\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (5) Types path */
|
|
||||||
clifmt.Align(" . custom types")
|
|
||||||
if !dirExists(tPath) {
|
|
||||||
fmt.Printf("missing\n")
|
|
||||||
compileTypes = false
|
|
||||||
} else {
|
|
||||||
fmt.Printf("ok\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !compileControllers && !compileTypes && !compileMiddlewares {
|
|
||||||
fmt.Printf("\n%s\n", clifmt.Info("Nothing to compile"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (4) Compile
|
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
/* (1) Create build output dir */
|
/* (1) Create build output dir */
|
||||||
buildPath := filepath.Join(projectPath, ".build")
|
buildPath := filepath.Join(schema.Root, ".build")
|
||||||
clifmt.Align(" . create build folder")
|
|
||||||
err = os.MkdirAll(buildPath, os.ModePerm)
|
err = os.MkdirAll(buildPath, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("error\n\n")
|
|
||||||
fmt.Printf("%s the directory %s cannot be created, check permissions.", clifmt.Warn(), clifmt.Color(33, buildPath))
|
fmt.Printf("%s the directory %s cannot be created, check permissions.", clifmt.Warn(), clifmt.Color(33, buildPath))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("ok\n")
|
|
||||||
|
|
||||||
/* (2) Compile controllers */
|
/* (2) Compile Types */
|
||||||
if compileControllers {
|
if len(schema.Types.Map) > 0 {
|
||||||
clifmt.Title("compile controllers")
|
|
||||||
err = compile(cPath, filepath.Join(projectPath, ".build/controller"))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%s compilation error: %s\n", clifmt.Warn(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Compile middlewares */
|
|
||||||
if compileMiddlewares {
|
|
||||||
clifmt.Title("compile middlewares")
|
|
||||||
err = compile(mPath, filepath.Join(projectPath, ".build/middleware"))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%s compilation error: %s\n", clifmt.Warn(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (4) Compile DEFAULT types */
|
|
||||||
clifmt.Title("compile default types")
|
|
||||||
err = compile(dtPath, filepath.Join(projectPath, ".build/type"))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%s compilation error: %s\n", clifmt.Warn(), err)
|
|
||||||
}
|
|
||||||
/* (5) Compile types */
|
|
||||||
if compileTypes {
|
|
||||||
clifmt.Title("compile types")
|
clifmt.Title("compile types")
|
||||||
err = compile(tPath, filepath.Join(projectPath, ".build/type"))
|
for name, upath := range schema.Types.Map {
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%s compilation error: %s\n", clifmt.Warn(), err)
|
fmt.Printf(" '%s'\n", clifmt.Color(33, name))
|
||||||
|
|
||||||
|
// Get useful paths
|
||||||
|
source := schema.Driver.Source(schema.Root, schema.Types.Folder, upath)
|
||||||
|
build := schema.Driver.Build(schema.Root, schema.Types.Folder, upath)
|
||||||
|
|
||||||
|
compile(source, build)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Compile controllers */
|
||||||
|
if len(schema.Controllers.Map) > 0 {
|
||||||
|
clifmt.Title("compile controllers")
|
||||||
|
for name, upath := range schema.Controllers.Map {
|
||||||
|
|
||||||
|
fmt.Printf(" '%s'\n", clifmt.Color(33, name))
|
||||||
|
|
||||||
|
// Get useful paths
|
||||||
|
source := schema.Driver.Source(schema.Root, schema.Controllers.Folder, upath)
|
||||||
|
build := schema.Driver.Build(schema.Root, schema.Controllers.Folder, upath)
|
||||||
|
|
||||||
|
compile(source, build)
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (4) Compile middlewares */
|
||||||
|
if len(schema.Middlewares.Map) > 0 {
|
||||||
|
clifmt.Title("compile middlewares")
|
||||||
|
for name, upath := range schema.Middlewares.Map {
|
||||||
|
|
||||||
|
fmt.Printf(" '%s'\n", clifmt.Color(33, name))
|
||||||
|
|
||||||
|
// Get useful paths
|
||||||
|
source := schema.Driver.Source(schema.Root, schema.Middlewares.Folder, upath)
|
||||||
|
build := schema.Driver.Build(schema.Root, schema.Middlewares.Folder, upath)
|
||||||
|
|
||||||
|
compile(source, build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (6) finished */
|
/* (6) finished */
|
||||||
fmt.Printf("\n[ %s | %.0f ms ] files are located inside the %s directory inside the project folder\n",
|
fmt.Printf("\n[ %s | %s ] files are located inside the %s directory inside the project folder\n",
|
||||||
clifmt.Color(32, "finished"),
|
clifmt.Color(32, "finished"),
|
||||||
float64(time.Now().UnixNano()-starttime)/1e6,
|
time.Now().Sub(starttime),
|
||||||
clifmt.Color(33, ".build"),
|
clifmt.Color(33, ".build"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,32 @@ import (
|
||||||
"git.xdrm.io/go/aicra/response"
|
"git.xdrm.io/go/aicra/response"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Name returns the driver name
|
// Name returns the driver name
|
||||||
func (d *Generic) Name() string { return "generic" }
|
func (d *Generic) Name() string { return "generic" }
|
||||||
|
|
||||||
|
// Path returns the universal path from the source path
|
||||||
|
func (d Generic) Path(_root, _folder, _src string) string {
|
||||||
|
return _src
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source returns the source path from the universal path
|
||||||
|
func (d Generic) Source(_root, _folder, _path string) string {
|
||||||
|
return filepath.Join(_root, _folder, _path)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns the build path from the universal path
|
||||||
|
func (d Generic) Build(_root, _folder, _path string) string {
|
||||||
|
return filepath.Join(_root, _folder, _path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiled returns whether the driver has to be build
|
||||||
|
func (d Generic) Compiled() bool { return false }
|
||||||
|
|
||||||
// RunController implements the Driver interface
|
// RunController implements the Driver interface
|
||||||
func (d *Generic) RunController(_path []string, _method string) (func(response.Arguments) response.Response, e.Error) {
|
func (d *Generic) RunController(_path []string, _method string) (func(response.Arguments) response.Response, e.Error) {
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,32 @@ import (
|
||||||
e "git.xdrm.io/go/aicra/err"
|
e "git.xdrm.io/go/aicra/err"
|
||||||
"git.xdrm.io/go/aicra/response"
|
"git.xdrm.io/go/aicra/response"
|
||||||
"net/http"
|
"net/http"
|
||||||
"plugin"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Name returns the driver name
|
// Name returns the driver name
|
||||||
func (d *Import) Name() string { return "import" }
|
func (d *Import) Name() string { return "import" }
|
||||||
|
|
||||||
|
// Path returns the universal path from the source path
|
||||||
|
func (d Import) Path(_root, _folder, _src string) string {
|
||||||
|
return strings.TrimSuffix(_src, ".go")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source returns the source path from the universal path
|
||||||
|
func (d Import) Source(_root, _folder, _path string) string {
|
||||||
|
return fmt.Sprintf("%s.go", filepath.Join(_root, _folder, _path))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns the build path from the universal path
|
||||||
|
func (d Import) Build(_root, _folder, _path string) string {
|
||||||
|
return filepath.Join(_root, _folder, _path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiled returns whether the driver has to be build
|
||||||
|
func (d Import) Compiled() bool { return false }
|
||||||
|
|
||||||
// RegisterController registers a new controller
|
// RegisterController registers a new controller
|
||||||
func (d *Import) RegisterController(_path string, _controller Controller) error {
|
func (d *Import) RegisterController(_path string, _controller Controller) error {
|
||||||
|
|
||||||
|
@ -62,7 +81,7 @@ func (d *Import) RegisterMiddlware(_path string, _middleware Middleware) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunController implements the Driver interface
|
// RunController implements the Driver interface
|
||||||
func (d *Import) RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error) {
|
func (d *Import) RunController(_path []string, _method string) (func(response.Arguments) response.Response, e.Error) {
|
||||||
|
|
||||||
/* (1) Build controller path */
|
/* (1) Build controller path */
|
||||||
path := strings.Join(_path, "-")
|
path := strings.Join(_path, "-")
|
||||||
|
@ -109,5 +128,5 @@ func (d *Import) LoadMiddleware(_path string) (func(http.Request, *[]string), er
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) Return middleware */
|
/* (3) Return middleware */
|
||||||
return mware, nil
|
return middleware.Inspect, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,32 @@ import (
|
||||||
"git.xdrm.io/go/aicra/err"
|
"git.xdrm.io/go/aicra/err"
|
||||||
"git.xdrm.io/go/aicra/response"
|
"git.xdrm.io/go/aicra/response"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
"plugin"
|
"plugin"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Name returns the driver name
|
// Name returns the driver name
|
||||||
func (d *Plugin) Name() string { return "plugin" }
|
func (d Plugin) Name() string { return "plugin" }
|
||||||
|
|
||||||
|
// Path returns the universal path from the source path
|
||||||
|
func (d Plugin) Path(_root, _folder, _src string) string {
|
||||||
|
return filepath.Dir(_src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source returns the source path from the universal path
|
||||||
|
func (d Plugin) Source(_root, _folder, _path string) string {
|
||||||
|
return filepath.Join(_root, _folder, _path, "main.go")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns the build path from the universal path
|
||||||
|
func (d Plugin) Build(_root, _folder, _path string) string {
|
||||||
|
return fmt.Sprintf("%s.so", filepath.Join(_root, ".build", _folder, _path))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiled returns whether the driver has to be build
|
||||||
|
func (d Plugin) Compiled() bool { return true }
|
||||||
|
|
||||||
// RunController implements the Driver interface
|
// RunController implements the Driver interface
|
||||||
func (d *Plugin) RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error) {
|
func (d *Plugin) RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error) {
|
||||||
|
|
|
@ -9,6 +9,11 @@ import (
|
||||||
// Driver defines the driver interface to load controller/middleware implementation or executables
|
// Driver defines the driver interface to load controller/middleware implementation or executables
|
||||||
type Driver interface {
|
type Driver interface {
|
||||||
Name() string
|
Name() string
|
||||||
|
Path(string, string, string) string
|
||||||
|
Source(string, string, string) string
|
||||||
|
Build(string, string, string) string
|
||||||
|
Compiled() bool
|
||||||
|
|
||||||
RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error)
|
RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error)
|
||||||
LoadMiddleware(_path string) (func(http.Request, *[]string), error)
|
LoadMiddleware(_path string) (func(http.Request, *[]string), error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package meta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"git.xdrm.io/go/aicra/driver"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// format inits the map if not set
|
||||||
|
func (b *builder) format() {
|
||||||
|
|
||||||
|
if b.Map == nil {
|
||||||
|
b.Map = make(map[string]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// InferFromFolder fills the 'Map' by browsing recursively the
|
||||||
|
// 'Folder' field
|
||||||
|
func (b *builder) InferFromFolder(_root string, _driver driver.Driver) {
|
||||||
|
|
||||||
|
// 1. ignore if no Folder
|
||||||
|
if len(b.Folder) < 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. If relative Folder, join to root
|
||||||
|
rootpath := filepath.Join(_root, b.Folder)
|
||||||
|
|
||||||
|
// 3. Walk
|
||||||
|
filepath.Walk(rootpath, func(path string, info os.FileInfo, err error) error {
|
||||||
|
|
||||||
|
// ignore dir
|
||||||
|
if err != nil || info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// format path
|
||||||
|
path, err = filepath.Rel(rootpath, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// extract universal path from the driver
|
||||||
|
upath := _driver.Path(_root, b.Folder, path)
|
||||||
|
|
||||||
|
// format name
|
||||||
|
name := upath
|
||||||
|
if name == "ROOT" {
|
||||||
|
name = ""
|
||||||
|
}
|
||||||
|
name = fmt.Sprintf("/%s", name)
|
||||||
|
|
||||||
|
// add to map
|
||||||
|
b.Map[name] = upath
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package meta
|
||||||
|
|
||||||
|
// Default contains the default values when ommited in json
|
||||||
|
var Default = Schema{
|
||||||
|
Host: "0.0.0.0",
|
||||||
|
Port: 80,
|
||||||
|
DriverName: "",
|
||||||
|
Types: &builder{
|
||||||
|
IgnoreBuiltIn: false,
|
||||||
|
Folder: "",
|
||||||
|
Map: nil,
|
||||||
|
},
|
||||||
|
Controllers: &builder{
|
||||||
|
IgnoreBuiltIn: true,
|
||||||
|
Folder: "",
|
||||||
|
Map: nil,
|
||||||
|
},
|
||||||
|
Middlewares: &builder{
|
||||||
|
IgnoreBuiltIn: true,
|
||||||
|
Folder: "",
|
||||||
|
Map: nil,
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
package meta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"git.xdrm.io/go/aicra/driver"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse extracts a Meta from a json config file (aicra.json)
|
||||||
|
func Parse(_path string) (*Schema, error) {
|
||||||
|
|
||||||
|
/* 1. ppen file */
|
||||||
|
file, err := os.Open(_path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("cannot open file")
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
/* 2. Init receiver dataset */
|
||||||
|
receiver := &Schema{}
|
||||||
|
|
||||||
|
/* 3. Decode json */
|
||||||
|
decoder := json.NewDecoder(file)
|
||||||
|
err = decoder.Decode(receiver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Error on invalid driver */
|
||||||
|
receiver.DriverName = strings.ToLower(receiver.DriverName)
|
||||||
|
switch receiver.DriverName {
|
||||||
|
case "generic":
|
||||||
|
receiver.Driver = &driver.Generic{}
|
||||||
|
case "plugin":
|
||||||
|
receiver.Driver = &driver.Plugin{}
|
||||||
|
case "import":
|
||||||
|
receiver.Driver = &driver.Import{}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, errors.New("invalid driver; choose from 'generic', 'plugin', and 'import'")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5. Fail if type map is set */
|
||||||
|
if receiver.Types.Map != nil {
|
||||||
|
return nil, errors.New("types must not feature the 'map'")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 6. Fail on absolute folders */
|
||||||
|
if len(receiver.Types.Folder) > 0 && filepath.IsAbs(receiver.Types.Folder) {
|
||||||
|
return nil, errors.New("types folder must be relative to root")
|
||||||
|
}
|
||||||
|
if len(receiver.Controllers.Folder) > 0 && filepath.IsAbs(receiver.Controllers.Folder) {
|
||||||
|
return nil, errors.New("controllers folder must be relative to root")
|
||||||
|
}
|
||||||
|
if len(receiver.Middlewares.Folder) > 0 && filepath.IsAbs(receiver.Middlewares.Folder) {
|
||||||
|
return nil, errors.New("middlewares folder must be relative to root")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 7. Format result (default values, etc) */
|
||||||
|
receiver.setDefaults()
|
||||||
|
|
||||||
|
return receiver, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// setDefaults sets defaults values and checks for missing data
|
||||||
|
func (m *Schema) setDefaults() {
|
||||||
|
|
||||||
|
// 1. extract absolute root folder
|
||||||
|
absroot, err := filepath.Abs(m.Root)
|
||||||
|
if err == nil {
|
||||||
|
m.Root = absroot
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. host
|
||||||
|
if len(m.Host) < 1 {
|
||||||
|
m.Host = Default.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. port
|
||||||
|
if m.Port == 0 {
|
||||||
|
m.Port = Default.Port
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Empty builders
|
||||||
|
if m.Types == nil {
|
||||||
|
m.Types = Default.Types
|
||||||
|
}
|
||||||
|
if m.Controllers == nil {
|
||||||
|
m.Controllers = Default.Controllers
|
||||||
|
}
|
||||||
|
if m.Middlewares == nil {
|
||||||
|
m.Middlewares = Default.Middlewares
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Init map if not set
|
||||||
|
m.Types.format()
|
||||||
|
m.Controllers.format()
|
||||||
|
m.Middlewares.format()
|
||||||
|
|
||||||
|
// 6. Infer Maps from Folders
|
||||||
|
m.Types.InferFromFolder(m.Root, m.Driver)
|
||||||
|
m.Controllers.InferFromFolder(m.Root, m.Driver)
|
||||||
|
m.Middlewares.InferFromFolder(m.Root, m.Driver)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package meta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.xdrm.io/go/aicra/driver"
|
||||||
|
)
|
||||||
|
|
||||||
|
type builder struct {
|
||||||
|
// IgnoreBuiltIn tells whether or not to ignore the built-in components
|
||||||
|
IgnoreBuiltIn bool `json:"default,ommitempty"`
|
||||||
|
|
||||||
|
// Folder is used to infer the 'Map' object
|
||||||
|
Folder string `json:"folder,ommitempty"`
|
||||||
|
|
||||||
|
// Map defines the association path=>file
|
||||||
|
Map map[string]string `json:"map,ommitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schema represents an AICRA configuration (not the API, the server, drivers, etc)
|
||||||
|
type Schema struct {
|
||||||
|
// Root is root of the project structure
|
||||||
|
Root string `json:"root"`
|
||||||
|
|
||||||
|
// Host is the hostname to listen to (default is 0.0.0.0)
|
||||||
|
Host string `json:"host,ommitempty"`
|
||||||
|
// Port is the port to listen to (default is 80)
|
||||||
|
Port uint16 `json:"port,ommitempty"`
|
||||||
|
|
||||||
|
// DriverName is the driver used to load the controllers and middlewares
|
||||||
|
// (default is 'plugin')
|
||||||
|
DriverName string `json:"driver"`
|
||||||
|
Driver driver.Driver
|
||||||
|
|
||||||
|
// Types defines :
|
||||||
|
// - the type folder
|
||||||
|
// - each type by 'name => path'
|
||||||
|
// - whether to load the built-in types
|
||||||
|
//
|
||||||
|
// types are ommited if not set (no default)
|
||||||
|
Types *builder `json:"types,ommitempty"`
|
||||||
|
|
||||||
|
// Controllers defines :
|
||||||
|
// - the controller folder (as a single string)
|
||||||
|
// - each controller by 'name => path' (as a map)
|
||||||
|
//
|
||||||
|
// (default is .build/controller)
|
||||||
|
Controllers *builder `json:"controllers,ommitempty"`
|
||||||
|
|
||||||
|
// Middlewares defines :
|
||||||
|
// - the middleware folder (as a single string)
|
||||||
|
// - each middleware by 'name => path' (as a map)
|
||||||
|
//
|
||||||
|
// (default is .build/middleware)
|
||||||
|
Middlewares *builder `json:"middlewares,ommitempty"`
|
||||||
|
}
|
Loading…
Reference in New Issue