Remove setup package and related functionality from the project

This commit is contained in:
Max 2024-11-29 16:44:31 +08:00
parent 83fc43cc52
commit 79f77618d3
7 changed files with 89 additions and 879 deletions

View file

@ -148,9 +148,6 @@ artifacts-linux: clean
echo "BASE=__yao_admin_root" > ../xgen-v1.0/packages/xgen/.env
cd ../xgen-v1.0 && pnpm install --no-frozen-lockfile && pnpm run build
# Setup UI
cd ../xgen-v1.0/packages/setup && pnpm install --no-frozen-lockfile && pnpm run build
# Init Application
cd ../yao-init && rm -rf .git
cd ../yao-init && rm -rf .gitignore
@ -169,7 +166,6 @@ artifacts-linux: clean
# ** new repository: https://github.com/YaoApp/dui.git **
mkdir -p .tmp/data/xgen
cp -r ./ui .tmp/data/ui
cp -r ../xgen-v1.0/packages/setup/build .tmp/data/xgen/setup
cp -r ../xgen-v1.0/packages/xgen/dist .tmp/data/xgen/v1.0
cp -r ../yao-init .tmp/data/init
cp -r yao .tmp/data/
@ -207,9 +203,6 @@ artifacts-macos: clean
echo "BASE=__yao_admin_root" > ../xgen-v1.0/packages/xgen/.env
cd ../xgen-v1.0 && pnpm install --no-frozen-lockfile && pnpm run build
# Setup UI
cd ../xgen-v1.0/packages/setup && pnpm install --no-frozen-lockfile && pnpm run build
# Init Application
cd ../yao-init && rm -rf .git
cd ../yao-init && rm -rf .gitignore
@ -228,7 +221,6 @@ artifacts-macos: clean
# ** new repository: https://github.com/YaoApp/dui.git **
mkdir -p .tmp/data/xgen
cp -r ./ui .tmp/data/ui
cp -r ../xgen-v1.0/packages/setup/build .tmp/data/xgen/setup
cp -r ../xgen-v1.0/packages/xgen/dist .tmp/data/xgen/v1.0
cp -r ../yao-init .tmp/data/init
cp -r yao .tmp/data/
@ -296,10 +288,6 @@ release: clean
echo "BASE=__yao_admin_root" > .tmp/xgen/v1.0/packages/xgen/.env
cd .tmp/xgen/v1.0 && pnpm install --no-frozen-lockfile && pnpm run build
# Setup UI
cd .tmp/xgen/v1.0/packages/setup && pnpm install --no-frozen-lockfile && pnpm run build
# Checkout init
git clone https://github.com/YaoApp/yao-init.git .tmp/yao-init
rm -rf .tmp/yao-init/.git
@ -320,7 +308,6 @@ release: clean
cp -r ./yao .tmp/data/yao
cp -r ./sui/libsui .tmp/data/libsui
cp -r .tmp/xgen/v0.9/dist .tmp/data/xgen/v0.9
cp -r .tmp/xgen/v1.0/packages/setup/build .tmp/data/xgen/setup
cp -r .tmp/xgen/v1.0/packages/xgen/dist .tmp/data/xgen/v1.0
cp -r .tmp/yao-init .tmp/data/init
go-bindata -fs -pkg data -o data/bindata.go -prefix ".tmp/data/" .tmp/data/...

View file

@ -49,17 +49,13 @@ var startCmd = &cobra.Command{
Boot()
// Setup
if setup.Check() {
go setup.Start()
select {
case <-setup.Done:
setup.Stop()
Boot()
break
case <-setup.Canceled:
isNewApp := false
if !setup.SourceExists() {
if err := install(); err != nil {
fmt.Println(color.RedString(L("Install: %s"), err.Error()))
os.Exit(1)
break
}
isNewApp = true
}
// force debug
@ -147,6 +143,11 @@ var startCmd = &cobra.Command{
printConnectors(false)
printStores(false)
printStudio(false, host)
// Print welcome message for the new application
if isNewApp {
printWelcome()
}
}
// Start Tasks
@ -161,7 +162,7 @@ var startCmd = &cobra.Command{
srv, err := service.Start(config.Conf)
defer func() {
service.Stop(srv)
fmt.Println(color.GreenString(L("✨EXITED✨")))
fmt.Println(color.GreenString(L("✨Exited successfully!")))
}()
if err != nil {
@ -193,11 +194,12 @@ var startCmd = &cobra.Command{
switch v {
case http.READY:
fmt.Println(color.GreenString(L("✨LISTENING✨")))
fmt.Println(color.GreenString(L("✨Server is up and running...")))
fmt.Println(color.BlackString("✨Ctrl+C to stop"))
break
case http.CLOSED:
fmt.Println(color.GreenString(L("✨EXITED✨")))
fmt.Println(color.GreenString(L("✨Exited successfully!")))
watchDone <- 1
return
@ -218,6 +220,30 @@ var startCmd = &cobra.Command{
},
}
func install() error {
// Copy the app source files from the binary
err := setup.Install(config.Conf.Root)
if err != nil {
return err
}
// Reload the application engine
Boot()
// load the application engine
err = engine.Load(config.Conf, engine.LoadOption{Action: "start"})
if err != nil {
return err
}
err = setup.Initialize(config.Conf.Root, config.Conf)
if err != nil {
return err
}
return nil
}
func adminRoot() (string, int) {
adminRoot := "/yao/"
if share.App.AdminRoot != "" {
@ -229,6 +255,15 @@ func adminRoot() (string, int) {
return adminRoot, adminRootLen
}
func printWelcome() {
fmt.Println(color.BlueString("\n---------------------------------"))
fmt.Println(color.BlueString(L("🎉 Welcome to Yao 🎉 ")))
fmt.Println(color.BlueString("---------------------------------"))
fmt.Println(color.WhiteString("📚 Documentation:"), color.BlueString("https://yaoapps.com/docs"))
fmt.Println(color.WhiteString("💬 Build App via Chat:"), color.BlueString("https://moapi.ai"))
fmt.Println("")
}
func printConnectors(silent bool) {
if len(connector.Connectors) == 0 {
@ -246,8 +281,8 @@ func printConnectors(silent bool) {
fmt.Println(color.WhiteString(L("Connectors List (%d)"), len(connector.Connectors)))
fmt.Println(color.WhiteString("---------------------------------"))
for name := range connector.Connectors {
fmt.Printf(color.CyanString("[Connector]"))
fmt.Printf(color.WhiteString(" %s\t loaded\n", name))
fmt.Print(color.CyanString("[Connector]"))
fmt.Print(color.WhiteString(" %s\t loaded\n", name))
}
}
@ -267,8 +302,8 @@ func printStores(silent bool) {
fmt.Println(color.WhiteString(L("Stores List (%d)"), len(connector.Connectors)))
fmt.Println(color.WhiteString("---------------------------------"))
for name := range store.Pools {
fmt.Printf(color.CyanString("[Store]"))
fmt.Printf(color.WhiteString(" %s\t loaded\n", name))
fmt.Print(color.CyanString("[Store]"))
fmt.Print(color.WhiteString(" %s\t loaded\n", name))
}
}
@ -285,13 +320,13 @@ func printStudio(silent bool, host string) {
fmt.Println(color.WhiteString("\n---------------------------------"))
fmt.Println(color.WhiteString(L("Yao Studio Server")))
fmt.Println(color.WhiteString("---------------------------------"))
fmt.Printf(color.CyanString("HOST : "))
fmt.Printf(color.WhiteString(" %s\n", config.Conf.Host))
fmt.Printf(color.CyanString("PORT : "))
fmt.Printf(color.WhiteString(" %d\n", config.Conf.Studio.Port))
fmt.Print(color.CyanString("HOST : "))
fmt.Print(color.WhiteString(" %s\n", config.Conf.Host))
fmt.Print(color.CyanString("PORT : "))
fmt.Print(color.WhiteString(" %d\n", config.Conf.Studio.Port))
if config.Conf.Studio.Auto {
fmt.Printf(color.CyanString("SECRET: "))
fmt.Printf(color.WhiteString(" %s\n", config.Conf.Studio.Secret))
fmt.Print(color.CyanString("SECRET: "))
fmt.Print(color.WhiteString(" %s\n", config.Conf.Studio.Secret))
}
}
@ -320,8 +355,8 @@ func printSchedules(silent bool) {
if sch.TaskName != "" {
process = fmt.Sprintf("Task: %s", sch.TaskName)
}
fmt.Printf(color.CyanString("[Schedule] %s %s", sch.Schedule, name))
fmt.Printf(color.WhiteString("\t%s\t%s\n", sch.Name, process))
fmt.Print(color.CyanString("[Schedule] %s %s", sch.Schedule, name))
fmt.Print(color.WhiteString("\t%s\t%s\n", sch.Name, process))
}
}
@ -342,8 +377,8 @@ func printTasks(silent bool) {
fmt.Println(color.WhiteString(L("Tasks List (%d)"), len(task.Tasks)))
fmt.Println(color.WhiteString("---------------------------------"))
for _, t := range task.Tasks {
fmt.Printf(color.CyanString("[Task] %s", t.Option.Name))
fmt.Printf(color.WhiteString("\t workers: %d\n", t.Option.WorkerNums))
fmt.Print(color.CyanString("[Task] %s", t.Option.Name))
fmt.Print(color.WhiteString("\t workers: %d\n", t.Option.WorkerNums))
}
}

View file

@ -1,45 +1,25 @@
package setup
import (
"fmt"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/yaoapp/xun/capsule"
"github.com/yaoapp/yao/config"
)
// Check if the app is installed
// true: start setup, false: start app
func Check() bool {
// check app source
if !appSourceExists() {
return true
}
// check env file
root := appRoot()
envfile := filepath.Join(root, ".env")
if _, err := os.Stat(envfile); err != nil && os.IsNotExist(err) {
return true
}
return false
// SourceExists check if the app source exists
func SourceExists() bool {
return appSourceExists()
}
func appSourceExists() bool {
appsource := appSource()
if strings.HasSuffix(appsource, ".yaz") || strings.HasPrefix(appsource, "::binary") {
return true
root := appRoot()
if isEmptyDir(root) {
return false
}
// check app.yao/app.json/app.jsonc
root := appRoot()
appfiles := []string{"app.yao", "app.json", "app.jsonc"}
exist := false
for _, appfile := range appfiles {
@ -53,63 +33,18 @@ func appSourceExists() bool {
return exist
}
// ValidateHosting host ports
func ValidateHosting(option map[string]string) error {
if option["YAO_PORT"] == "" {
return fmt.Errorf("监听端口必须填写")
}
if option["YAO_STUDIO_PORT"] == option["YAO_PORT"] {
return fmt.Errorf("监听端口和 Studio 端口不能相同")
}
if option["YAO_PORT"] != SetupPort {
conn, _ := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", option["YAO_PORT"]), time.Second)
if conn != nil {
defer conn.Close()
return fmt.Errorf("监听端口 %s 已被占用", option["YAO_PORT"])
}
}
if option["YAO_STUDIO_PORT"] != SetupPort {
conn, _ := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", option["YAO_STUDIO_PORT"]), time.Second)
if conn != nil {
defer conn.Close()
return fmt.Errorf("Studio 端口 %s 已被占用", option["YAO_STUDIO_PORT"])
}
}
return nil
}
// ValidateDB db connection
func ValidateDB(option map[string]string) error {
driver, dsn, err := getDSN(option)
func isEmptyDir(dir string) bool {
f, err := os.Open(dir)
if err != nil {
return fmt.Errorf("连接失败 %s", err.Error())
return true
}
defer f.Close()
m, err := capsule.Add("validate", driver, dsn)
files, err := f.Readdir(0)
if err != nil {
return fmt.Errorf("连接失败 %s", err.Error())
return true
}
conn, err := m.Primary()
if err != nil {
return fmt.Errorf("连接失败 %s", err.Error())
}
err = conn.Ping(2 * time.Second)
if err != nil {
return fmt.Errorf("连接失败 %s", err.Error())
}
return nil
}
func appSource() string {
return os.Getenv("YAO_APP_SOURCE")
return len(files) == 0
}
func appRoot() string {
@ -118,16 +53,14 @@ func appRoot() string {
if root == "" {
path, err := os.Getwd()
if err != nil {
printError("无法获取应用目录: %s", err)
Stop()
printError("Can't get the application directory: %s", err)
}
root = path
}
root, err := filepath.Abs(root)
if err != nil {
printError("无法获取应用目录: %s", err)
Stop()
printError("Can't get the application directory: %s", err)
}
return root
@ -139,35 +72,3 @@ func getConfig() (config.Config, error) {
cfg := config.LoadFrom(envfile)
return cfg, nil
}
func hasInstalled(cfg config.Config) bool {
return false
// switch cfg.DB.Driver {
// case "sqlite3":
// if cfg.DB.Primary != nil && len(cfg.DB.Primary) > 0 {
// dbfile, err := filepath.Abs(cfg.DB.Primary[0])
// if err != nil {
// return false
// }
// if _, err := os.Stat(dbfile); err != nil && os.IsNotExist(err) {
// return false
// }
// return false
// }
// break
// case "mysql":
// if cfg.DB.Primary != nil && len(cfg.DB.Primary) > 0 {
// return true
// }
// break
// }
// return false
}

View file

@ -1,65 +0,0 @@
package setup
import (
"os"
"path/filepath"
"github.com/joho/godotenv"
)
func envSet(file, name, value string) error {
file, err := filepath.Abs(file)
if err != nil {
dir := filepath.Dir(file)
err := os.MkdirAll(dir, os.ModePerm)
if err != nil && !os.IsExist(err) {
return err
}
}
if _, err := os.Stat(file); err != nil && os.IsNotExist(err) {
err = os.WriteFile(file, []byte{}, 0644)
if err != nil {
return err
}
err = godotenv.Write(map[string]string{"YAO_ENV": "development"}, file)
if err != nil {
return err
}
}
vars, err := godotenv.Read(file)
if err != nil {
return err
}
vars[name] = value
return godotenv.Write(vars, file)
}
func envGet(file, name string) (string, error) {
v := os.Getenv(name)
if v != "" {
return v, nil
}
vars, err := godotenv.Read(file)
if err == nil {
return "", err
}
return vars[name], nil
}
func envHas(file, name string) (bool, error) {
v, err := envGet(file, name)
if err != nil {
return false, nil
}
return v != "", nil
}

View file

@ -1,265 +0,0 @@
package setup
import (
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/gin-gonic/gin"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/xun"
"github.com/yaoapp/yao/engine"
"github.com/yaoapp/yao/widgets/app"
)
// recovered custom recovered
func recovered(c *gin.Context, recovered interface{}) {
var code = http.StatusInternalServerError
if err, ok := recovered.(string); ok {
c.JSON(code, xun.R{
"code": code,
"message": fmt.Sprintf("%s", err),
})
} else if err, ok := recovered.(exception.Exception); ok {
code = err.Code
c.JSON(code, xun.R{
"code": code,
"message": err.Message,
})
} else if err, ok := recovered.(*exception.Exception); ok {
code = err.Code
c.JSON(code, xun.R{
"code": code,
"message": err.Message,
})
} else {
c.JSON(code, xun.R{
"code": code,
"message": fmt.Sprintf("%v", recovered),
})
}
c.AbortWithStatus(code)
}
// {
// "env": {
// "YAO_LANG": "中文",
// "YAO_ENV": "开发模式(推荐)",
// "YAO_PORT": "5099",
// "YAO_STUDIO_PORT": "5077"
// },
// "db": {
// "type": "sqlite",
// "option.file": "db/yao.db"
// }
// }
func runSetup(c *gin.Context) {
payload := getSetting(c)
cfg, err := getConfig()
if err != nil {
c.JSON(500, gin.H{"code": 500, "message": err.Error()})
return
}
if !Check() {
c.JSON(403, gin.H{"code": 400, "message": "应用已安装, 删除 .env 文件和 db 目录后重试"})
return
}
err = Install(payload)
if err != nil {
c.JSON(500, gin.H{"code": 500, "message": err.Error()})
return
}
// Reload Config
cfg, err = getConfig()
if err != nil {
c.JSON(500, gin.H{"code": 500, "message": err.Error()})
return
}
err = engine.Load(cfg, engine.LoadOption{})
if err != nil {
c.JSON(500, gin.H{"code": 500, "message": err.Error()})
return
}
// Return
urls, err := AdminURL(cfg)
if err != nil {
c.JSON(500, gin.H{"code": 500, "message": err.Error()})
return
}
adminRoot := "yao"
if app.Setting.AdminRoot != "" {
adminRoot = app.Setting.AdminRoot
}
adminRoot = strings.Trim(adminRoot, "/")
c.JSON(200, gin.H{
"code": 200,
"message": "安装成功",
"urls": urls,
"port": cfg.Port,
"root": adminRoot,
})
Complete()
}
func runCheck(c *gin.Context) {
payload := getCheck(c)
dbOption, err := getDBOption(map[string]map[string]string{"db": payload})
if err != nil {
c.JSON(500, gin.H{"code": 500, "message": err.Error()})
return
}
err = ValidateDB(dbOption)
if err != nil {
c.JSON(500, gin.H{"code": 500, "message": err.Error()})
return
}
c.JSON(200, gin.H{"code": 200})
}
func getCheck(c *gin.Context) map[string]string {
var payload map[string]string
err := c.ShouldBindJSON(&payload)
if err != nil {
c.JSON(500, gin.H{"code": 400, "message": err.Error()})
c.Abort()
return nil
}
return payload
}
func getSetting(c *gin.Context) map[string]map[string]string {
var payload map[string]map[string]string
err := c.ShouldBindJSON(&payload)
if err != nil {
c.JSON(500, gin.H{"code": 400, "message": err.Error()})
c.Abort()
return nil
}
return payload
}
func getENVOption(payload map[string]map[string]string) (map[string]string, error) {
env, has := payload["env"]
if !has {
return nil, fmt.Errorf("缺少服务配置信息")
}
if env["YAO_ENV"] == "开发模式(推荐)" {
env["YAO_ENV"] = "development"
} else {
env["YAO_ENV"] = "production"
}
if env["YAO_LANG"] == "中文" {
env["YAO_LANG"] = "zh-cn"
} else {
env["YAO_LANG"] = "en-us"
}
return env, nil
}
func getDBOption(payload map[string]map[string]string) (map[string]string, error) {
db, has := payload["db"]
if !has {
return nil, fmt.Errorf("缺少数据库配置信息")
}
dbOption := map[string]string{}
switch db["type"] {
case "", "sqlite", "sqlite3":
dbOption["type"] = "sqlite3"
dbOption["file"] = db["option.file"]
return dbOption, nil
case "mysql":
dbOption["type"] = "mysql"
dbOption["db"] = db["option.db"]
dbOption["host"] = db["option.host.host"]
dbOption["port"] = db["option.host.port"]
dbOption["user"] = db["option.host.user"]
dbOption["pass"] = db["option.host.pass"]
return dbOption, nil
}
return nil, fmt.Errorf("数据库驱动暂不支持")
}
func getDSN(dbOption map[string]string) (string, string, error) {
switch dbOption["type"] {
case "", "sqlite", "sqlite3":
root := appRoot()
var err error
db := filepath.Join("db", "yao.db")
if v, has := dbOption["file"]; has {
db = v
}
if !strings.HasPrefix(db, "/") {
db = filepath.Join(root, db)
db, err = filepath.Abs(db)
if err != nil && !os.IsNotExist(err) {
return "", "", err
}
}
dir := filepath.Dir(db)
err = os.MkdirAll(dir, os.ModePerm)
if err != nil && !os.IsExist(err) {
return "", "", err
}
return "sqlite3", db, nil
case "mysql":
db := "yao"
if v, has := dbOption["db"]; has {
db = v
}
host := "127.0.0.1"
if v, has := dbOption["host"]; has {
host = v
}
port := "3306"
if v, has := dbOption["port"]; has {
port = v
}
user := "root"
if v, has := dbOption["user"]; has {
user = v
}
pass := ""
if v, has := dbOption["pass"]; has {
pass = v
}
return "mysql", fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, pass, host, port, db), nil
}
return "", "", fmt.Errorf("driver does not support")
}

View file

@ -5,7 +5,6 @@ import (
"os"
"path/filepath"
"strings"
"time"
"github.com/google/uuid"
"github.com/yaoapp/gou/model"
@ -14,127 +13,14 @@ import (
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/data"
"github.com/yaoapp/yao/engine"
"github.com/yaoapp/yao/studio"
"github.com/yaoapp/yao/widgets/app"
)
// Install app install
//
// {
// "env": {
// "YAO_LANG": "中文",
// "YAO_ENV": "开发模式(推荐)",
// "YAO_PORT": "5099",
// "YAO_STUDIO_PORT": "5077"
// },
// "db": {
// "type": "sqlite",
// "option.file": "db/yao.db"
// }
// }
//
// {
// "env": {
// "YAO_LANG": "中文",
// "YAO_ENV": "开发模式(推荐)",
// "YAO_PORT": "5099",
// "YAO_STUDIO_PORT": "5077"
// },
// "db": {
// "type": "mysql",
// "option.db": "yao",
// "option.host.host": "127.0.0.1",
// "option.host.port": "3306",
// "option.host.user": "root",
// "option.host.pass": "123456"
// }
// }
func Install(payload map[string]map[string]string) error {
// Install the app to the root directory
func Install(root string) error {
dbOption, err := getDBOption(payload)
if err != nil {
return err
}
err = ValidateDB(dbOption)
if err != nil {
return err
}
envOption, err := getENVOption(payload)
if err != nil {
return err
}
err = ValidateHosting(envOption)
if err != nil {
return err
}
root := appRoot()
err = makeService(root, "0.0.0.0", envOption["YAO_PORT"], envOption["YAO_STUDIO_PORT"], envOption["YAO_LANG"])
if err != nil {
return err
}
err = makeDB(root, dbOption)
if err != nil {
return err
}
err = makeSession(root)
if err != nil {
return err
}
err = makeLog(root)
if err != nil {
return err
}
err = makeDirs(root)
if err != nil {
return err
}
err = makeInit(root)
if err != nil {
return err
}
cfg, err := getConfig()
if err != nil {
return err
}
// Load engine
err = engine.Load(cfg, engine.LoadOption{
Action: "install",
})
if err != nil {
return err
}
defer func() {
engine.Unload()
time.Sleep(time.Millisecond * 200)
}()
// Load Studio
err = studio.Load(cfg)
if err != nil {
return err
}
// Migrage & Setup
err = makeMigrate(root, cfg)
if err != nil {
return err
}
err = makeSetup(root, cfg)
// Copy the init source files
err := makeInit(root)
if err != nil {
return err
}
@ -142,113 +28,21 @@ func Install(payload map[string]map[string]string) error {
return nil
}
func makeService(root string, host string, port string, studioPort string, lang string) error {
file := filepath.Join(root, ".env")
err := envSet(file, "YAO_HOST", host)
// Initialize the installed app
func Initialize(root string, cfg config.Config) error {
// Migration
err := makeMigrate()
if err != nil {
return err
}
err = envSet(file, "YAO_PORT", port)
// Execute the setup hook
err = makeSetup(cfg)
if err != nil {
return err
}
err = envSet(file, "YAO_STUDIO_PORT", studioPort)
if err != nil {
return err
}
return envSet(file, "YAO_LANG", lang)
}
func makeDB(root string, option map[string]string) error {
driver, dsn, err := getDSN(option)
if driver != "mysql" && driver != "sqlite3" {
return fmt.Errorf("数据库驱动应该为: mysql/sqlite3")
}
file := filepath.Join(root, ".env")
if err != nil {
return err
}
err = envSet(file, "YAO_DB_DRIVER", driver)
if err != nil {
return err
}
return envSet(file, "YAO_DB_PRIMARY", dsn)
}
func makeSession(root string) error {
file := filepath.Join(root, ".env")
if has, _ := envHas(file, "YAO_SESSION_STORE"); has {
return nil
}
if has, _ := envHas(file, "YAO_SESSION_FILE"); has {
return nil
}
err := os.MkdirAll(filepath.Join(root, "data"), os.ModePerm)
if err != nil && !os.IsExist(err) {
return err
}
err = envSet(file, "YAO_SESSION_STORE", "file")
if err != nil {
return err
}
ssfile := filepath.Join(root, "db", ".session")
return envSet(file, "YAO_SESSION_FILE", ssfile)
}
func makeLog(root string) error {
file := filepath.Join(root, ".env")
if has, _ := envHas(file, "YAO_LOG_MODE"); has {
return nil
}
if has, _ := envHas(file, "YAO_LOG"); has {
return nil
}
err := os.MkdirAll(filepath.Join(root, "data"), os.ModePerm)
if err != nil && !os.IsExist(err) {
return err
}
err = envSet(file, "YAO_LOG_MODE", "TEXT")
if err != nil {
return err
}
logfile := filepath.Join(root, "logs", "application.log")
return envSet(file, "YAO_LOG", logfile)
}
func makeDirs(root string) error {
if !appSourceExists() {
err := os.MkdirAll(filepath.Join(root, "public"), os.ModePerm)
if err != nil && !os.IsExist(err) {
return err
}
}
err := os.MkdirAll(filepath.Join(root, "logs"), os.ModePerm)
if err != nil && !os.IsExist(err) {
return err
}
err = os.MkdirAll(filepath.Join(root, "db"), os.ModePerm)
if err != nil && !os.IsExist(err) {
return err
}
return nil
}
@ -285,7 +79,7 @@ func makeInit(root string) error {
return nil
}
func makeMigrate(root string, cfg config.Config) error {
func makeMigrate() error {
// Do Stuff Here
for _, mod := range model.Models {
@ -308,7 +102,7 @@ func makeMigrate(root string, cfg config.Config) error {
return nil
}
func makeSetup(root string, cfg config.Config) error {
func makeSetup(cfg config.Config) error {
if app.Setting != nil && app.Setting.Setup != "" {

View file

@ -3,164 +3,12 @@ package setup
import (
"fmt"
"net"
"net/http"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"github.com/fatih/color"
"github.com/gin-gonic/gin"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/data"
"github.com/yaoapp/yao/engine"
"github.com/yaoapp/yao/share"
"github.com/yaoapp/yao/widgets/app"
)
// SetupPort setup port
var SetupPort string = "5099"
// XGenSetupServer XGen Setup
var XGenSetupServer http.Handler = http.FileServer(data.Setup())
// Done check done
var Done = make(chan bool, 1)
// shutdown check done
var shutdown = make(chan bool, 1)
// Canceled check if setup is canceld
var Canceled = make(chan bool, 1)
// Start start the studio api server
func Start() (err error) {
// recive interrupt signal
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
errCh := make(chan error, 1)
// Set router
gin.SetMode(gin.ReleaseMode)
router := gin.New()
if os.Getenv("YAO_SETUP_DEV") != "" {
fmt.Println(color.WhiteString("\nSETUP DEV: %s\n", os.Getenv("YAO_SETUP_DEV")))
}
router.Use(func(c *gin.Context) {
length := len(c.Request.URL.Path)
if length >= 5 && c.Request.URL.Path[0:5] == "/api/" {
c.Next()
return
}
if os.Getenv("YAO_SETUP_DEV") != "" {
root, err := filepath.Abs(os.Getenv("YAO_SETUP_DEV"))
if err != nil {
printError("%s", err)
}
static := http.FileServer(http.Dir(root))
static.ServeHTTP(c.Writer, c.Request)
return
}
// Setup Pages
XGenSetupServer.ServeHTTP(c.Writer, c.Request)
return
}, gin.CustomRecovery(recovered))
router.POST("/api/__yao/app/check", runCheck)
router.POST("/api/__yao/app/setup", runSetup)
// Server setting
addr := fmt.Sprintf(":%s", SetupPort)
// Listen
l, err := net.Listen("tcp4", addr)
if err != nil {
addr = ":0"
l, err = net.Listen("tcp4", addr)
if err != nil {
return err
}
}
srv := &http.Server{
Addr: addr,
Handler: router,
}
defer func() {
// printInfo("[Setup] %s Close Serve", addr)
err = srv.Close()
if err != nil {
printError("[Setup] Error (%v)", err)
}
}()
// start serve
go func() {
// printInfo("[Setup] Starting: %s", addr)
if err := srv.Serve(l); err != nil && err != http.ErrServerClosed {
errCh <- err
}
}()
welcome(l)
select {
case <-shutdown:
printInfo("Setup Shutdown")
return err
case <-interrupt:
printInfo("Setup Interrupt")
Canceled <- true
return err
case err := <-errCh:
printError("Setup Error: ", err)
Canceled <- true
return err
}
}
// Complete stop the studio api server
func Complete() {
engine.Unload()
Done <- true
}
// Stop stop the studio api server
func Stop() {
shutdown <- true
}
// AdminURL get admin url
func AdminURL(cfg config.Config) ([]string, error) {
urls, err := URLs(cfg)
if err != nil {
return nil, err
}
adminRoot := "yao"
if app.Setting.AdminRoot != "" {
adminRoot = app.Setting.AdminRoot
}
adminRoot = strings.Trim(adminRoot, "/")
for i := range urls {
urls[i] = fmt.Sprintf("%s/%s/", urls[i], adminRoot)
}
return urls, nil
}
// URLs get admin url
func URLs(cfg config.Config) ([]string, error) {
@ -176,31 +24,6 @@ func URLs(cfg config.Config) ([]string, error) {
return ips, nil
}
func welcome(l net.Listener) {
fmt.Println(color.WhiteString("---------------------------------"))
fmt.Println(color.WhiteString("Yao Application Setup v%s", share.VERSION))
fmt.Println(color.WhiteString("---------------------------------"))
ips, err := Ips()
if err != nil {
printError("Error: ", err.Error())
}
addr := strings.Split(l.Addr().String(), ":")
if len(addr) != 2 {
printError("Error: can't get port")
}
port := addr[1]
fmt.Println(color.WhiteString("\nOpen URL in the browser to continue:\n"))
for _, ip := range ips {
printInfo("http://%s:%s", ip, port)
}
fmt.Println()
SetupPort = port
}
func printError(message string, args ...interface{}) {
fmt.Println(color.RedString(message, args...))
os.Exit(1)