yao/setup/install.go
2022-10-28 11:58:05 +08:00

1254 lines
24 KiB
Go

package setup
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/fs"
"github.com/yaoapp/gou/fs/dsl"
"github.com/yaoapp/gou/fs/system"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/engine"
"github.com/yaoapp/yao/share"
"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(option map[string]map[string]string) error {
env, has := option["env"]
if !has {
return fmt.Errorf("缺少服务配置信息")
}
db, has := option["db"]
if !has {
return 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"
}
dbName := db["type"]
dbOption := map[string]string{}
switch dbName {
case "", "sqlite", "sqlite3":
dbName = "sqlite3"
dbOption["file"] = db["option.file"]
break
case "mysql":
dbName = "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"]
break
}
root := appRoot()
err := makeService(root, "0.0.0.0", env["YAO_PORT"], env["YAO_STUDIO_PORT"], env["YAO_LANG"])
if err != nil {
return err
}
err = makeDB(root, dbName, 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 = makeDemoWidgets(root)
if err != nil {
return err
}
err = makeMigrate(root)
if err != nil {
return err
}
err = makeSetup(root)
if err != nil {
return err
}
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)
if err != nil {
return err
}
err = envSet(file, "YAO_PORT", port)
if err != nil {
return err
}
return envSet(file, "YAO_LANG", lang)
}
func makeDB(root string, driver string, option map[string]string) error {
if driver != "mysql" && driver != "sqlite3" {
return fmt.Errorf("数据库驱动应该为: mysql/sqlite3")
}
file := filepath.Join(root, ".env")
dsn := ""
switch driver {
case "mysql":
db := "yao"
if v, has := option["db"]; has {
db = v
}
host := "127.0.0.1"
if v, has := option["host"]; has {
host = v
}
port := "3306"
if v, has := option["port"]; has {
port = v
}
user := "root"
if v, has := option["user"]; has {
user = v
}
pass := ""
if v, has := option["pass"]; has {
pass = v
}
err := envSet(file, "YAO_DB_DRIVER", driver)
if err != nil {
return err
}
dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, pass, host, port, db)
return envSet(file, "YAO_DB_PRIMARY", dsn)
case "sqlite", "sqlite3":
var err error
db := filepath.Join("db", "yao.db")
if v, has := option["db"]; has {
file = 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
}
err = envSet(file, "YAO_DB_DRIVER", "sqlite3")
if err != nil {
return err
}
return envSet(file, "YAO_DB_PRIMARY", db)
}
return fmt.Errorf("数据库驱动应该为: mysql/sqlite3")
}
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, "data", ".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 {
err := os.MkdirAll(filepath.Join(root, "public"), os.ModePerm)
if err != nil && !os.IsExist(err) {
return err
}
err = os.MkdirAll(filepath.Join(root, "services"), os.ModePerm)
if err != nil && !os.IsExist(err) {
return err
}
err = os.MkdirAll(filepath.Join(root, "studio"), 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
}
return nil
}
func makeDemoWidgets(root string) error {
dsl := dsl.New(root)
// make app
ok, err := makeAppWidget(dsl, root)
if err != nil || !ok {
return err
}
// make flows
err = makeMenuFlowWidget(dsl, root)
if err != nil {
return err
}
// make logins
err = makeLoginWidget(dsl, root)
if err != nil {
return err
}
// make models
err = makeModelWidget(dsl, root)
if err != nil {
return err
}
// make tables & forms
err = makeTableFormWidget(dsl, root)
if err != nil {
return err
}
// make chart
err = makeChartWidget(dsl, root)
if err != nil {
return err
}
// make scripts
err = makeScript(root)
if err != nil {
return err
}
// make scripts
err = makeLang(root)
if err != nil {
return err
}
// make index page
err = makeIndexPage(root)
if err != nil {
return err
}
return nil
}
func makeAppWidget(dsl fs.FileSystem, root string) (bool, error) {
file := filepath.Join("app.json")
if _, err := os.Stat(filepath.Join(root, file)); err == nil { // exists
return false, nil
}
_, err := dsl.WriteFile(file, []byte(fmt.Sprintf(`
{
"xgen": "1.0",
"name": "::Demo Application",
"short": "::Demo",
"description": "::Another yao application",
"version": "%s",
"adminRoot": "admin",
"setup": "scripts.demo.Data",
"menu": {
"process": "flows.app.menu",
"args": ["demo"]
},
"optional": {
"hideNotification": true,
"hideSetting": false
}
}
`, share.VERSION)), 0644)
if err != nil {
return false, err
}
return true, nil
}
func makeMenuFlowWidget(dsl fs.FileSystem, root string) error {
file := filepath.Join("flows", "app", "menu.flow.json")
if _, err := os.Stat(filepath.Join(root, file)); err == nil { // exists
return nil
}
_, err := dsl.WriteFile(file, []byte(`
{
"name": "APP Menu",
"nodes": [],
"output": [
{
"blocks": 0,
"icon": "icon-activity",
"id": 1,
"name": "图表",
"parent": null,
"path": "/x/Chart/dashboard",
"visible_menu": 0
},
{
"blocks": 0,
"icon": "icon-book",
"id": 2,
"name": "表格",
"parent": null,
"path": "/x/Table/pet",
"visible_menu": 1,
"children": [
{
"blocks": 0,
"icon": "icon-book",
"name": "宠物列表",
"id": 2010,
"parent": 2,
"path": "/x/Table/pet",
"visible_menu": 1
}
]
},
{
"blocks": 0,
"icon": "icon-clipboard",
"id": 2,
"name": "表单",
"parent": null,
"path": "/x/Form/pet/1/edit",
"visible_menu": 1,
"children": [
{
"blocks": 0,
"icon": "icon-clipboard",
"name": "编辑模式",
"id": 2010,
"parent": 2,
"path": "/x/Form/pet/1/edit",
"visible_menu": 1
},
{
"blocks": 0,
"icon": "icon-clipboard",
"name": "查看模式",
"id": 2010,
"parent": 2,
"path": "/x/Form/pet/1/view",
"visible_menu": 1
}
]
}
]
}
`), 0644)
if err != nil {
return err
}
return nil
}
func makeLoginWidget(dsl fs.FileSystem, root string) error {
file := filepath.Join("logins", "admin.login.json")
if _, err := os.Stat(filepath.Join(root, file)); err == nil { // exists
return nil
}
_, err := dsl.WriteFile(file, []byte(`
{
"name": "::Admin Login",
"action": {
"process": "yao.login.Admin",
"args": [":payload"]
},
"layout": {
"entry": "/x/Chart/dashboard",
"slogan": "::Make Your Dream With Yao App Engine",
"site": "https://yaoapps.com?from=instance-admin-login"
}
}
`), 0644)
if err != nil {
return err
}
file = filepath.Join("logins", "user.login.json")
if _, err := os.Stat(filepath.Join(root, file)); err == nil { // exists
return nil
}
_, err = dsl.WriteFile(file, []byte(`
{
"name": "::User Login",
"action": {
"process": "scripts.user.Login",
"args": [":payload"]
},
"layout": {
"entry": "/x/Table/pet",
"slogan": "::Make Your Dream With Yao App Engine",
"site": "https://yaoapps.com/from=instance-user-login"
}
}
`), 0644)
if err != nil {
return err
}
return nil
}
func makeModelWidget(dsl fs.FileSystem, root string) error {
file := filepath.Join("models", "pet.mod.json")
if _, err := os.Stat(filepath.Join(root, file)); err == nil { // exists
return nil
}
_, err := dsl.WriteFile(file, []byte(`
{
"name": "Pet",
"table": { "name": "pet", "comment": "宠物表" },
"columns": [
{ "name": "id", "comment": "ID", "type": "ID" },
{
"name": "name",
"comment": "昵称",
"type": "string",
"length": 80,
"index": true,
"nullable": true
},
{
"name": "type",
"comment": "类型",
"type": "enum",
"option": ["cat", "dog", "others"],
"index": true
},
{
"name": "status",
"comment": "入院状态",
"type": "enum",
"option": ["checked", "curing", "cured"],
"index": true
},
{
"name": "mode",
"comment": "状态",
"type": "enum",
"option": ["enabled", "disabled"],
"index": true
},
{
"name": "online",
"comment": "是否在线",
"type": "boolean",
"default": false,
"index": true
},
{
"name": "curing_status",
"comment": "治疗状态",
"type": "enum",
"default": "0",
"option": ["0", "1", "2"],
"index": true
},
{
"name": "stay",
"comment": "入院时间",
"type": "integer"
},
{
"name": "cost",
"comment": "花费",
"type": "integer"
},
{
"name": "doctor_id",
"type": "integer",
"comment": "相关职工",
"nullable": true
},
{
"name": "images",
"type": "json",
"comment": "相关图片",
"nullable": true
},
{
"name": "test_string",
"comment": "测试字段(字符串)",
"type": "string",
"nullable": true
},
{
"name": "test_number",
"comment": "测试字段(数字)",
"type": "integer",
"nullable": true
},
{
"name": "test_array",
"comment": "测试字段(数组)",
"type": "json",
"nullable": true
}
],
"relations": {},
"values": [],
"indexes": [],
"option": { "timestamps": true,"soft_deletes": true }
}
`), 0644)
if err != nil {
return err
}
return nil
}
func makeTableFormWidget(dsl fs.FileSystem, root string) error {
file := filepath.Join("tables", "pet.tab.json")
if _, err := os.Stat(filepath.Join(root, file)); err == nil { // exists
return nil
}
_, err := dsl.WriteFile(file, []byte(`
{
"name": "::Pet Admin Bind Model",
"action": {
"bind": { "model": "pet", "option": {} }
}
}
`), 0644)
if err != nil {
return err
}
file = filepath.Join("forms", "pet.form.json")
if _, err := os.Stat(filepath.Join(root, file)); err == nil { // exists
return nil
}
_, err = dsl.WriteFile(file, []byte(`
{
"name": "::Pet Admin Bind Table",
"action": {
"bind": { "table": "pet", "option": {} }
}
}
`), 0644)
if err != nil {
return err
}
return nil
}
func makeChartWidget(dsl fs.FileSystem, root string) error {
file := filepath.Join("charts", "dashboard.chart.json")
if _, err := os.Stat(filepath.Join(root, file)); err == nil { // exists
return nil
}
_, err := dsl.WriteFile(file, []byte(`
{
"name": "宠物医院数据图表",
"config":{"full":false},
"action": {
"before:data": "scripts.stat.BeforeData",
"data": { "process": "scripts.stat.Data", "default": ["2022-09-20"] },
"after:data": "scripts.stat.AfterData"
},
"layout": {
"operation": {
"actions": [
{
"title": "跳转至大屏",
"icon": "icon-airplay",
"action": { "Common.historyPush": { "pathname": "/x/Cool/demo" } }
}
]
},
"filter": {
"columns": [{ "name": "时间区间", "width": 6 }]
},
"chart": {
"columns": [
{ "name": "宠物数量", "width": 6 },
{ "name": "宠物类型", "width": 6 },
{ "name": "当月收入", "width": 6 },
{ "name": "医师数量", "width": 6 },
{ "name": "宠物数量_上月", "width": 6 },
{ "name": "宠物类型_上月", "width": 6 },
{ "name": "当月收入_上月", "width": 6 },
{ "name": "医师数量_上月", "width": 6 },
{ "name": "收入", "width": 8 },
{ "name": "支出", "width": 8 },
{ "name": "综合评分", "width": 8 },
{ "name": "收入_折线图", "width": 8 },
{ "name": "支出_折线图", "width": 8 },
{ "name": "综合评分_折线图", "width": 8 },
{ "name": "类型排布", "width": 12 },
{ "name": "状态分布", "width": 12 },
{ "name": "综合消费", "width": 24 }
]
}
},
"fields": {
"filter": {
"时间区间": {
"bind": "range",
"edit": { "type": "RangePicker", "props": {} }
},
"状态": {
"bind": "status",
"edit": {
"type": "Select",
"props": {
"xProps": {
"$remote": {
"process": "models.pet.Get",
"query": { "select": "name,status", "limit": 2 }
}
}
}
}
}
},
"chart": {
"收入": {
"bind": "income",
"link": "/x/Table/pet",
"out": "scripts.stat.Income",
"view": {
"type": "NumberChart",
"props": {
"chartHeight": 150,
"prefix": "¥",
"decimals": 2,
"nameKey": "date",
"valueKey": "value"
}
}
},
"支出": {
"bind": "cost",
"link": "/x/Table/pet",
"view": {
"type": "NumberChart",
"props": {
"chartHeight": 150,
"color": "red",
"prefix": "¥",
"decimals": 2,
"nameKey": "date",
"valueKey": "value"
}
}
},
"综合评分": {
"bind": "rate",
"link": "/x/Table/pet",
"view": {
"type": "NumberChart",
"props": {
"chartHeight": 150,
"color": "orange",
"unit": "分",
"decimals": 1,
"nameKey": "date",
"valueKey": "value"
}
}
},
"收入_折线图": {
"bind": "income",
"link": "/x/Table/pet",
"view": {
"type": "NumberChart",
"props": {
"cardStyle": { "padding": 0 },
"type": "line",
"chartHeight": 120,
"prefix": "¥",
"decimals": 2,
"nameKey": "date",
"valueKey": "value"
}
}
},
"支出_折线图": {
"bind": "cost",
"link": "/x/Table/pet",
"view": {
"type": "NumberChart",
"props": {
"cardStyle": { "padding": 0 },
"type": "line",
"chartHeight": 120,
"color": "red",
"prefix": "¥",
"decimals": 2,
"nameKey": "date",
"valueKey": "value"
}
}
},
"综合评分_折线图": {
"bind": "rate",
"link": "/x/Table/pet",
"view": {
"type": "NumberChart",
"props": {
"cardStyle": { "padding": 0 },
"type": "line",
"chartHeight": 120,
"color": "orange",
"unit": "分",
"decimals": 1,
"nameKey": "date",
"valueKey": "value"
}
}
},
"宠物数量": {
"bind": "pet_count",
"link": "/x/Table/pet",
"view": { "type": "Number", "props": { "unit": "个" } }
},
"宠物类型": {
"bind": "pet_type",
"view": { "type": "Number", "props": { "unit": "种" } }
},
"当月收入": {
"bind": "income_monthly",
"view": { "type": "Number", "props": { "unit": "元" } }
},
"医师数量": {
"bind": "doctor_count",
"view": { "type": "Number", "props": { "unit": "个" } }
},
"宠物数量_上月": {
"bind": "prev_pet_count",
"link": "/x/Table/pet",
"view": {
"type": "Number",
"props": {
"cardStyle": { "padding": 0 },
"unit": "个",
"prev_title": "上月数据"
}
}
},
"宠物类型_上月": {
"bind": "prev_pet_type",
"link": "/x/Table/pet",
"view": {
"type": "Number",
"props": {
"cardStyle": { "padding": 0 },
"unit": "种",
"prev_title": "上月数据"
}
}
},
"当月收入_上月": {
"bind": "prev_income_monthly",
"link": "/x/Table/pet",
"view": {
"type": "Number",
"props": {
"cardStyle": { "padding": 0 },
"unit": "元",
"prev_title": "上月数据"
}
}
},
"医师数量_上月": {
"bind": "prev_doctor_count",
"link": "/x/Table/pet",
"view": {
"type": "Number",
"props": {
"cardStyle": { "padding": 0 },
"unit": "个",
"prev_title": "上月数据"
}
}
},
"类型排布": {
"bind": "datasource_type",
"link": "/x/Table/pet",
"view": {
"type": "Pie",
"props": {
"height": 240,
"nameKey": "type",
"series": [
{
"valueKey": "count",
"roseType": "area",
"radius": [10, 100],
"center": ["60%", "50%"],
"itemStyle": { "borderRadius": 6 }
}
]
}
},
"refer": {
"type": "Table",
"props": {
"columns": [
{ "title": "类型", "dataIndex": "type" },
{ "title": "数量", "dataIndex": "count" }
]
}
}
},
"状态分布": {
"bind": "datasource_status",
"view": {
"type": "Bar",
"props": {
"height": 240,
"nameKey": "status",
"axisLabel": { "interval": 0, "fontSize": 12 },
"series": [
{
"valueKey": "count",
"type": "bar",
"colorBy": "data",
"itemStyle": { "borderRadius": 6 },
"splitLine": { "show": false },
"axisLabel": { "show": false }
}
]
}
},
"refer": {
"type": "Table",
"props": {
"columns": [
{ "title": "状态", "dataIndex": "status" },
{ "title": "数量", "dataIndex": "count" }
]
}
}
},
"综合消费": {
"bind": "datasource_cost",
"view": {
"type": "LineBar",
"props": {
"height": 240,
"nameKey": "name",
"axisLabel": { "interval": 0, "fontSize": 12 },
"series": [
{
"valueKey": "stay",
"type": "line",
"smooth": true,
"symbolSize": 8,
"itemStyle": { "borderRadius": 6 },
"splitLine": { "show": false },
"axisLabel": { "show": false }
},
{
"valueKey": "cost",
"type": "bar",
"itemStyle": { "borderRadius": 6 },
"splitLine": { "show": false },
"axisLabel": { "show": false }
}
]
}
}
}
}
}
}
`), 0644)
if err != nil {
return err
}
return nil
}
func makeScript(root string) error {
fs := system.New(filepath.Join(root, "scripts"))
file := "demo.js"
if _, err := os.Stat(filepath.Join(root, "scripts", file)); err == nil { // exists
return nil
}
_, err := fs.WriteFile(file, []byte(`
/**
* Demo Data
*/
function Data() {
return Process(
"yao.table.Insert",
"pet",
["name", "type", "status", "mode", "stay", "cost", "doctor_id"],
[
["Cookie", "cat", "checked", "enabled", 200, 105, 1],
["Baby", "dog", "checked", "enabled", 186, 24, 1],
["Poo", "others", "checked", "enabled", 199, 66, 1],
]
);
}
`), 0644)
if err != nil {
return err
}
file = filepath.Join("stat.js")
if _, err := os.Stat(filepath.Join(root, "scripts", file)); err == nil { // exists
return nil
}
_, err = fs.WriteFile(file, []byte(`
/**
* before:data hook
* @param {*} params
* @returns
*/
function BeforeData(params) {
log.Info("[chart] before data hook: %s", JSON.stringify(params));
return [params];
}
/**
* after:data hook
* @param {*} data
* @returns
*/
function AfterData(data) {
log.Info("[chart] after data hook: %s", JSON.stringify(data));
return data;
}
/**
* Get Data
* @param {*} params
*/
function Data(params) {
log.Info("[chart] process data query: %s", JSON.stringify(params));
return {
income: [
{ value: 40300, date: "2022-1-1" },
{ value: 50800, date: "2022-2-1" },
{ value: 31300, date: "2022-3-1" },
{ value: 48800, date: "2022-4-1" },
{ value: 69900, date: "2022-5-1" },
{ value: 37800, date: "2022-6-1" },
],
cost: [
{ value: 28100, date: "2022-1-1" },
{ value: 23000, date: "2022-2-1" },
{ value: 29300, date: "2022-3-1" },
{ value: 26700, date: "2022-4-1" },
{ value: 26400, date: "2022-5-1" },
{ value: 31200, date: "2022-6-1" },
],
rate: [
{ value: 8.0, date: "2022-1-1" },
{ value: 7.6, date: "2022-2-1" },
{ value: 9.1, date: "2022-3-1" },
{ value: 8.4, date: "2022-4-1" },
{ value: 6.9, date: "2022-5-1" },
{ value: 9.0, date: "2022-6-1" },
],
pet_count: 54,
pet_type: 8,
income_monthly: 68900,
doctor_count: 23,
prev_pet_count: { current: 54, prev: 45 },
prev_pet_type: { current: 8, prev: 13 },
prev_income_monthly: { current: 68900, prev: 92000 },
prev_doctor_count: { current: 23, prev: 27 },
datasource_type: [
{ type: "猫猫", count: 18 },
{ type: "狗狗", count: 6 },
{ type: "其他", count: 3 },
],
datasource_status: [
{ status: "已查看", count: 3 },
{ status: "治疗中", count: 12 },
{ status: "已治愈", count: 9 },
],
datasource_cost: [
{ name: "毛毛", stay: 3, cost: 2000 },
{ name: "阿布", stay: 6, cost: 4200 },
{ name: "咪咪", stay: 7, cost: 6000 },
{ name: "狗蛋", stay: 1, cost: 1000 },
],
};
}
/**
* Compute out
* @param {*} field
* @param {*} value
* @param {*} data
* @returns
*/
function Income(field, value, data) {
log.Info(
"[chart] Income Compute: %s",
JSON.stringify({ field: field, value: value, data: data })
);
return value;
}
`), 0644)
if err != nil {
return err
}
return nil
}
func makeLang(root string) error {
fs := system.New(filepath.Join(root, "langs"))
file := filepath.Join("zh-cn", "global.yml")
if _, err := os.Stat(filepath.Join(root, "langs", file)); err == nil { // exists
return nil
}
_, err := fs.WriteFile(file, []byte(`
Demo: 演示
Demo Application: 示例应用
Another yao application: 又一个 YAO 应用`), 0644)
if err != nil {
return err
}
file = filepath.Join("zh-hk", "langs", "global.yml")
if _, err := os.Stat(filepath.Join(root, file)); err == nil { // exists
return nil
}
_, err = fs.WriteFile(file, []byte(`
Demo: 演示
Demo Application: 示例應用
Another yao application: 又一個YAO應用`), 0644)
if err != nil {
return err
}
return nil
}
func makeIndexPage(root string) error {
fs := system.New(filepath.Join(root, "public"))
file := "index.html"
if _, err := os.Stat(filepath.Join(root, "public", file)); err == nil { // exists
return nil
}
_, err := fs.WriteFile(file, []byte(`
It works!`), 0644)
if err != nil {
return err
}
return nil
}
func makeMigrate(root string) error {
cfg, err := getConfig()
if err != nil {
return err
}
err = engine.Load(cfg)
if err != nil {
return err
}
// Do Stuff Here
for _, mod := range gou.Models {
has, err := mod.HasTable()
if err != nil {
return err
}
if has {
log.Warn("%s (%s) table already exists", mod.ID, mod.MetaData.Table.Name)
continue
}
err = mod.Migrate(false)
if err != nil {
return err
}
}
return nil
}
func makeSetup(root string) error {
cfg, err := getConfig()
if err != nil {
return err
}
err = engine.Load(cfg)
if err != nil {
return err
}
if app.Setting != nil && app.Setting.Setup != "" {
p, err := gou.ProcessOf(app.Setting.Setup)
if err != nil {
return err
}
_, err = p.Exec()
if err != nil {
return err
}
}
return nil
}