1
0
mirror of https://github.com/beego/bee.git synced 2024-11-14 06:40:54 +00:00
bee/apiapp.go

689 lines
17 KiB
Go
Raw Normal View History

2013-10-30 23:54:53 +00:00
// Copyright 2013 bee authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
2013-09-11 10:18:02 +00:00
package main
import (
"fmt"
"os"
path "path/filepath"
"strings"
)
var cmdApiapp = &Command{
// CustomFlags: true,
UsageLine: "api [appname]",
Short: "create an API beego application",
Long: `
Create an API beego application.
2013-09-11 10:18:02 +00:00
2014-08-08 16:55:55 +00:00
bee api [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test]
-tables: a list of table names separated by ',' (default is empty, indicating all tables)
-driver: [mysql | postgres | sqlite] (default: mysql)
2014-08-08 16:55:55 +00:00
-conn: the connection string used by the driver, the default is ''
2014-08-22 08:16:22 +00:00
e.g. for mysql: root:@tcp(127.0.0.1:3306)/test
e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
2014-08-08 16:55:55 +00:00
If 'conn' argument is empty, bee api creates an example API application,
when 'conn' argument is provided, bee api generates an API application based
on the existing database.
2013-09-11 10:18:02 +00:00
The command 'api' creates a folder named [appname] and inside the folder deploy
the following files/directories structure:
2013-09-11 10:18:02 +00:00
conf
app.conf
controllers
2014-06-24 06:32:17 +00:00
object.go
user.go
2013-12-23 15:28:31 +00:00
routers
router.go
tests
default_test.go
2013-09-11 10:18:02 +00:00
main.go
models
object.go
user.go
2013-09-11 10:18:02 +00:00
`,
}
2014-06-24 06:32:17 +00:00
var apiconf = `appname = {{.Appname}}
2013-09-11 10:18:02 +00:00
httpport = 8080
runmode = dev
autorender = false
copyrequestbody = true
2014-06-24 06:32:17 +00:00
EnableDocs = true
2013-09-11 10:18:02 +00:00
`
var apiMaingo = `package main
import (
2014-06-24 06:32:17 +00:00
_ "{{.Appname}}/docs"
2013-12-23 16:00:52 +00:00
_ "{{.Appname}}/routers"
2013-09-11 10:18:02 +00:00
2014-06-24 06:32:17 +00:00
"github.com/astaxie/beego"
)
2013-09-11 10:18:02 +00:00
func main() {
2016-01-06 03:55:56 +00:00
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
2014-06-24 06:32:17 +00:00
}
2013-09-11 10:18:02 +00:00
beego.Run()
}
`
2014-08-08 16:55:55 +00:00
var apiMainconngo = `package main
import (
_ "{{.Appname}}/docs"
_ "{{.Appname}}/routers"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
{{.DriverPkg}}
2014-08-08 16:55:55 +00:00
)
func init() {
orm.RegisterDataBase("default", "{{.DriverName}}", "{{.conn}}")
2014-08-08 16:55:55 +00:00
}
func main() {
2016-01-06 03:55:56 +00:00
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
2014-08-08 16:55:55 +00:00
}
beego.Run()
}
`
2014-06-24 06:32:17 +00:00
var apirouter = `// @APIVersion 1.0.0
// @Title beego Test API
// @Description beego has a very cool tools to autogenerate documents for your API
// @Contact astaxie@gmail.com
// @TermsOfServiceUrl http://beego.me/
// @License Apache 2.0
// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html
package routers
2013-12-23 15:28:31 +00:00
import (
"{{.Appname}}/controllers"
2014-06-24 06:32:17 +00:00
2013-12-23 15:28:31 +00:00
"github.com/astaxie/beego"
)
func init() {
2014-06-24 06:32:17 +00:00
ns := beego.NewNamespace("/v1",
beego.NSNamespace("/object",
beego.NSInclude(
&controllers.ObjectController{},
),
),
beego.NSNamespace("/user",
beego.NSInclude(
&controllers.UserController{},
),
),
)
beego.AddNamespace(ns)
2013-12-23 15:28:31 +00:00
}
`
2013-09-11 10:18:02 +00:00
var apiModels = `package models
import (
"errors"
"strconv"
"time"
)
var (
Objects map[string]*Object
)
type Object struct {
ObjectId string
Score int64
PlayerName string
}
func init() {
Objects = make(map[string]*Object)
Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"}
Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"}
}
func AddOne(object Object) (ObjectId string) {
object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10)
Objects[object.ObjectId] = &object
return object.ObjectId
}
func GetOne(ObjectId string) (object *Object, err error) {
if v, ok := Objects[ObjectId]; ok {
return v, nil
}
return nil, errors.New("ObjectId Not Exist")
}
func GetAll() map[string]*Object {
return Objects
}
func Update(ObjectId string, Score int64) (err error) {
if v, ok := Objects[ObjectId]; ok {
v.Score = Score
return nil
}
return errors.New("ObjectId Not Exist")
}
func Delete(ObjectId string) {
delete(Objects, ObjectId)
}
2014-06-24 06:32:17 +00:00
`
var apiModels2 = `package models
import (
"errors"
"strconv"
"time"
)
var (
UserList map[string]*User
)
func init() {
UserList = make(map[string]*User)
u := User{"user_11111", "astaxie", "11111", Profile{"male", 20, "Singapore", "astaxie@gmail.com"}}
UserList["user_11111"] = &u
}
type User struct {
Id string
Username string
Password string
Profile Profile
}
type Profile struct {
Gender string
Age int
Address string
Email string
}
func AddUser(u User) string {
u.Id = "user_" + strconv.FormatInt(time.Now().UnixNano(), 10)
UserList[u.Id] = &u
return u.Id
}
func GetUser(uid string) (u *User, err error) {
if u, ok := UserList[uid]; ok {
return u, nil
}
return nil, errors.New("User not exists")
}
func GetAllUsers() map[string]*User {
return UserList
}
func UpdateUser(uid string, uu *User) (a *User, err error) {
if u, ok := UserList[uid]; ok {
if uu.Username != "" {
u.Username = uu.Username
}
if uu.Password != "" {
u.Password = uu.Password
}
if uu.Profile.Age != 0 {
u.Profile.Age = uu.Profile.Age
}
if uu.Profile.Address != "" {
u.Profile.Address = uu.Profile.Address
}
if uu.Profile.Gender != "" {
u.Profile.Gender = uu.Profile.Gender
}
if uu.Profile.Email != "" {
u.Profile.Email = uu.Profile.Email
}
return u, nil
}
return nil, errors.New("User Not Exist")
}
func Login(username, password string) bool {
for _, u := range UserList {
if u.Username == username && u.Password == password {
return true
}
}
return false
}
func DeleteUser(uid string) {
delete(UserList, uid)
}
2013-09-11 10:18:02 +00:00
`
var apiControllers = `package controllers
import (
2014-06-24 06:32:17 +00:00
"{{.Appname}}/models"
2013-09-11 10:18:02 +00:00
"encoding/json"
2014-06-24 06:32:17 +00:00
2013-09-11 10:18:02 +00:00
"github.com/astaxie/beego"
)
2014-06-24 06:32:17 +00:00
// Operations about object
2013-09-13 07:32:58 +00:00
type ObjectController struct {
2013-09-11 10:18:02 +00:00
beego.Controller
}
2014-06-24 06:32:17 +00:00
// @Title create
// @Description create object
// @Param body body models.Object true "The object content"
// @Success 200 {string} models.Object.Id
// @Failure 403 body is empty
// @router / [post]
2014-11-05 14:48:09 +00:00
func (o *ObjectController) Post() {
2013-09-11 10:18:02 +00:00
var ob models.Object
2014-11-05 14:48:09 +00:00
json.Unmarshal(o.Ctx.Input.RequestBody, &ob)
2013-09-11 10:18:02 +00:00
objectid := models.AddOne(ob)
2014-11-05 14:48:09 +00:00
o.Data["json"] = map[string]string{"ObjectId": objectid}
o.ServeJSON()
2013-09-11 10:18:02 +00:00
}
2014-06-24 06:32:17 +00:00
// @Title Get
// @Description find object by objectid
// @Param objectId path string true "the objectid you want to get"
// @Success 200 {object} models.Object
// @Failure 403 :objectId is empty
// @router /:objectId [get]
2014-11-05 14:48:09 +00:00
func (o *ObjectController) Get() {
2016-01-06 03:55:56 +00:00
objectId := o.Ctx.Input.Param(":objectId")
2013-09-11 10:18:02 +00:00
if objectId != "" {
ob, err := models.GetOne(objectId)
if err != nil {
2015-09-27 23:42:11 +00:00
o.Data["json"] = err.Error()
2013-09-11 10:18:02 +00:00
} else {
2014-11-05 14:48:09 +00:00
o.Data["json"] = ob
2013-09-11 10:18:02 +00:00
}
}
o.ServeJSON()
2013-09-11 10:18:02 +00:00
}
2014-06-24 06:32:17 +00:00
// @Title GetAll
// @Description get all objects
// @Success 200 {object} models.Object
// @Failure 403 :objectId is empty
// @router / [get]
2014-11-05 14:48:09 +00:00
func (o *ObjectController) GetAll() {
2014-06-24 06:32:17 +00:00
obs := models.GetAll()
2014-11-05 14:48:09 +00:00
o.Data["json"] = obs
o.ServeJSON()
2014-06-24 06:32:17 +00:00
}
// @Title update
// @Description update the object
// @Param objectId path string true "The objectid you want to update"
// @Param body body models.Object true "The body"
// @Success 200 {object} models.Object
// @Failure 403 :objectId is empty
// @router /:objectId [put]
2014-11-05 14:48:09 +00:00
func (o *ObjectController) Put() {
2016-01-06 03:55:56 +00:00
objectId := o.Ctx.Input.Param(":objectId")
2013-09-11 10:18:02 +00:00
var ob models.Object
2014-11-05 14:48:09 +00:00
json.Unmarshal(o.Ctx.Input.RequestBody, &ob)
2013-09-11 10:18:02 +00:00
err := models.Update(objectId, ob.Score)
if err != nil {
2015-09-27 23:42:11 +00:00
o.Data["json"] = err.Error()
2013-09-11 10:18:02 +00:00
} else {
2014-11-05 14:48:09 +00:00
o.Data["json"] = "update success!"
2013-09-11 10:18:02 +00:00
}
o.ServeJSON()
2013-09-11 10:18:02 +00:00
}
2014-06-24 06:32:17 +00:00
// @Title delete
// @Description delete the object
// @Param objectId path string true "The objectId you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 objectId is empty
// @router /:objectId [delete]
2014-11-05 14:48:09 +00:00
func (o *ObjectController) Delete() {
2016-01-06 03:55:56 +00:00
objectId := o.Ctx.Input.Param(":objectId")
2013-09-11 10:18:02 +00:00
models.Delete(objectId)
2014-11-05 14:48:09 +00:00
o.Data["json"] = "delete success!"
o.ServeJSON()
2013-09-11 10:18:02 +00:00
}
2014-06-24 06:32:17 +00:00
`
var apiControllers2 = `package controllers
import (
"{{.Appname}}/models"
"encoding/json"
"github.com/astaxie/beego"
)
// Operations about Users
type UserController struct {
beego.Controller
}
// @Title createUser
// @Description create users
// @Param body body models.User true "body for user content"
// @Success 200 {int} models.User.Id
// @Failure 403 body is empty
// @router / [post]
func (u *UserController) Post() {
var user models.User
json.Unmarshal(u.Ctx.Input.RequestBody, &user)
uid := models.AddUser(user)
u.Data["json"] = map[string]string{"uid": uid}
u.ServeJSON()
2014-06-24 06:32:17 +00:00
}
// @Title Get
// @Description get all Users
// @Success 200 {object} models.User
// @router / [get]
func (u *UserController) GetAll() {
users := models.GetAllUsers()
u.Data["json"] = users
u.ServeJSON()
2014-06-24 06:32:17 +00:00
}
// @Title Get
// @Description get user by uid
// @Param uid path string true "The key for staticblock"
// @Success 200 {object} models.User
// @Failure 403 :uid is empty
// @router /:uid [get]
func (u *UserController) Get() {
uid := u.GetString(":uid")
if uid != "" {
user, err := models.GetUser(uid)
if err != nil {
2015-09-27 23:42:11 +00:00
u.Data["json"] = err.Error()
2014-06-24 06:32:17 +00:00
} else {
u.Data["json"] = user
}
}
u.ServeJSON()
2014-06-24 06:32:17 +00:00
}
// @Title update
// @Description update the user
// @Param uid path string true "The uid you want to update"
// @Param body body models.User true "body for user content"
// @Success 200 {object} models.User
// @Failure 403 :uid is not int
// @router /:uid [put]
func (u *UserController) Put() {
uid := u.GetString(":uid")
if uid != "" {
var user models.User
json.Unmarshal(u.Ctx.Input.RequestBody, &user)
uu, err := models.UpdateUser(uid, &user)
if err != nil {
2015-09-27 23:42:11 +00:00
u.Data["json"] = err.Error()
2014-06-24 06:32:17 +00:00
} else {
u.Data["json"] = uu
}
}
u.ServeJSON()
2014-06-24 06:32:17 +00:00
}
// @Title delete
// @Description delete the user
// @Param uid path string true "The uid you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 uid is empty
// @router /:uid [delete]
func (u *UserController) Delete() {
uid := u.GetString(":uid")
models.DeleteUser(uid)
u.Data["json"] = "delete success!"
u.ServeJSON()
2014-06-24 06:32:17 +00:00
}
// @Title login
// @Description Logs user into the system
// @Param username query string true "The username for login"
// @Param password query string true "The password for login"
// @Success 200 {string} login success
2014-06-24 06:32:17 +00:00
// @Failure 403 user not exist
// @router /login [get]
func (u *UserController) Login() {
username := u.GetString("username")
password := u.GetString("password")
if models.Login(username, password) {
u.Data["json"] = "login success"
} else {
u.Data["json"] = "user not exist"
}
u.ServeJSON()
2014-06-24 06:32:17 +00:00
}
// @Title logout
// @Description Logs out current logged in user session
// @Success 200 {string} logout success
// @router /logout [get]
func (u *UserController) Logout() {
u.Data["json"] = "logout success"
u.ServeJSON()
2014-06-24 06:32:17 +00:00
}
2013-09-11 10:18:02 +00:00
`
2013-08-27 14:35:48 +00:00
2013-12-23 15:28:31 +00:00
var apiTests = `package test
2013-08-27 14:35:48 +00:00
import (
2013-12-23 15:28:31 +00:00
"net/http"
"net/http/httptest"
"testing"
2014-04-03 08:46:47 +00:00
"runtime"
"path/filepath"
2013-12-23 16:00:52 +00:00
_ "{{.Appname}}/routers"
2013-12-23 15:28:31 +00:00
"github.com/astaxie/beego"
. "github.com/smartystreets/goconvey/convey"
2013-08-27 14:35:48 +00:00
)
2014-04-03 08:41:44 +00:00
func init() {
_, file, _, _ := runtime.Caller(1)
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator))))
2014-04-03 08:41:44 +00:00
beego.TestBeegoInit(apppath)
}
2013-12-23 15:28:31 +00:00
// TestGet is a sample to run an endpoint test
func TestGet(t *testing.T) {
2014-10-01 18:45:16 +00:00
r, _ := http.NewRequest("GET", "/v1/object", nil)
2013-12-23 15:28:31 +00:00
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, r)
2013-12-23 15:28:31 +00:00
beego.Trace("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String())
2013-12-23 15:28:31 +00:00
Convey("Subject: Test Station Endpoint\n", t, func() {
Convey("Status Code Should Be 200", func() {
So(w.Code, ShouldEqual, 200)
})
Convey("The Result Should Not Be Empty", func() {
So(w.Body.Len(), ShouldBeGreaterThan, 0)
})
})
2013-08-27 14:35:48 +00:00
}
`
2013-09-11 10:18:02 +00:00
func init() {
cmdApiapp.Run = createapi
2014-08-08 16:55:55 +00:00
cmdApiapp.Flag.Var(&tables, "tables", "specify tables to generate model")
cmdApiapp.Flag.Var(&driver, "driver", "database driver: mysql, postgresql, etc.")
cmdApiapp.Flag.Var(&conn, "conn", "connection string used by the driver to connect to a database instance")
2013-09-11 10:18:02 +00:00
}
2014-08-15 09:38:51 +00:00
func createapi(cmd *Command, args []string) int {
2014-08-08 16:55:55 +00:00
curpath, _ := os.Getwd()
if len(args) < 1 {
ColorLog("[ERRO] Argument [appname] is missing\n")
os.Exit(2)
}
2014-08-08 16:55:55 +00:00
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
2013-09-11 10:18:02 +00:00
}
apppath, packpath, err := checkEnv(args[0])
if err != nil {
fmt.Println(err)
os.Exit(2)
}
2014-08-08 16:55:55 +00:00
if driver == "" {
driver = "mysql"
}
if conn == "" {
}
2013-09-11 10:18:02 +00:00
os.MkdirAll(apppath, 0755)
fmt.Println("create app folder:", apppath)
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Println("create conf:", path.Join(apppath, "conf"))
os.Mkdir(path.Join(apppath, "controllers"), 0755)
fmt.Println("create controllers:", path.Join(apppath, "controllers"))
2014-06-24 06:32:17 +00:00
os.Mkdir(path.Join(apppath, "docs"), 0755)
fmt.Println("create docs:", path.Join(apppath, "docs"))
2013-09-11 10:18:02 +00:00
os.Mkdir(path.Join(apppath, "tests"), 0755)
fmt.Println("create tests:", path.Join(apppath, "tests"))
fmt.Println("create conf app.conf:", path.Join(apppath, "conf", "app.conf"))
writetofile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(apiconf, "{{.Appname}}", args[0], -1))
2014-08-08 16:55:55 +00:00
if conn != "" {
fmt.Println("create main.go:", path.Join(apppath, "main.go"))
maingoContent := strings.Replace(apiMainconngo, "{{.Appname}}", packpath, -1)
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1)
if driver == "mysql" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1)
} else if driver == "postgres" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1)
}
2014-08-08 16:55:55 +00:00
writetofile(path.Join(apppath, "main.go"),
strings.Replace(
maingoContent,
2014-08-08 16:55:55 +00:00
"{{.conn}}",
conn.String(),
-1,
),
)
ColorLog("[INFO] Using '%s' as 'driver'\n", driver)
ColorLog("[INFO] Using '%s' as 'conn'\n", conn)
2014-08-22 03:23:28 +00:00
ColorLog("[INFO] Using '%s' as 'tables'\n", tables)
2014-08-22 03:20:29 +00:00
generateAppcode(string(driver), string(conn), "3", string(tables), path.Join(curpath, args[0]))
2014-08-08 16:55:55 +00:00
} else {
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Println("create models:", path.Join(apppath, "models"))
os.Mkdir(path.Join(apppath, "routers"), 0755)
fmt.Println(path.Join(apppath, "routers") + string(path.Separator))
fmt.Println("create controllers object.go:", path.Join(apppath, "controllers", "object.go"))
writetofile(path.Join(apppath, "controllers", "object.go"),
strings.Replace(apiControllers, "{{.Appname}}", packpath, -1))
2013-09-11 10:18:02 +00:00
2014-08-08 16:55:55 +00:00
fmt.Println("create controllers user.go:", path.Join(apppath, "controllers", "user.go"))
writetofile(path.Join(apppath, "controllers", "user.go"),
strings.Replace(apiControllers2, "{{.Appname}}", packpath, -1))
2014-06-24 06:32:17 +00:00
2014-08-08 16:55:55 +00:00
fmt.Println("create tests default.go:", path.Join(apppath, "tests", "default_test.go"))
writetofile(path.Join(apppath, "tests", "default_test.go"),
strings.Replace(apiTests, "{{.Appname}}", packpath, -1))
2013-12-23 15:28:31 +00:00
2014-08-08 16:55:55 +00:00
fmt.Println("create routers router.go:", path.Join(apppath, "routers", "router.go"))
writetofile(path.Join(apppath, "routers", "router.go"),
strings.Replace(apirouter, "{{.Appname}}", packpath, -1))
2013-08-27 14:35:48 +00:00
2014-08-08 16:55:55 +00:00
fmt.Println("create models object.go:", path.Join(apppath, "models", "object.go"))
writetofile(path.Join(apppath, "models", "object.go"), apiModels)
2013-09-11 10:18:02 +00:00
2014-08-08 16:55:55 +00:00
fmt.Println("create models user.go:", path.Join(apppath, "models", "user.go"))
writetofile(path.Join(apppath, "models", "user.go"), apiModels2)
2014-06-24 06:32:17 +00:00
2014-08-08 16:55:55 +00:00
fmt.Println("create docs doc.go:", path.Join(apppath, "docs", "doc.go"))
writetofile(path.Join(apppath, "docs", "doc.go"), "package docs")
2014-06-24 06:32:17 +00:00
2014-08-08 16:55:55 +00:00
fmt.Println("create main.go:", path.Join(apppath, "main.go"))
writetofile(path.Join(apppath, "main.go"),
strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1))
}
2014-08-22 03:20:29 +00:00
return 0
2013-09-11 10:18:02 +00:00
}
func checkEnv(appname string) (apppath, packpath string, err error) {
curpath, err := os.Getwd()
if err != nil {
return
}
gopath := os.Getenv("GOPATH")
Debugf("gopath:%s", gopath)
if gopath == "" {
err = fmt.Errorf("you should set GOPATH in the env")
return
}
appsrcpath := ""
haspath := false
wgopath := path.SplitList(gopath)
for _, wg := range wgopath {
wg = path.Join(wg, "src")
2013-09-11 10:18:02 +00:00
if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
haspath = true
appsrcpath = wg
break
}
wg, _ = path.EvalSymlinks(wg)
if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
2013-09-11 10:18:02 +00:00
haspath = true
appsrcpath = wg
break
}
}
if !haspath {
err = fmt.Errorf("can't create application outside of GOPATH `%s`\n"+
"you first should `cd $GOPATH%ssrc` then use create\n", gopath, string(path.Separator))
return
}
apppath = path.Join(curpath, appname)
if _, e := os.Stat(apppath); os.IsNotExist(e) == false {
err = fmt.Errorf("path `%s` exists, can not create app without remove it\n", apppath)
return
}
packpath = strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/")
return
}