Refactor!

create sub packages
delete unused code
delete code from not use command cmdRouter,cmdTest, cmdRundocs
make command plugins
check with gosimple,staticcheck,go vet,unused,unconvert
This commit is contained in:
Sergey Lanzman 2017-03-07 01:58:53 +02:00
parent 74baba4f63
commit c538bfbc8f
47 changed files with 1838 additions and 2467 deletions

View File

@ -1,280 +0,0 @@
// 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.
package main
import (
"bytes"
"errors"
"fmt"
"go/ast"
gobuild "go/build"
"go/doc"
"go/parser"
"go/token"
"io"
"io/ioutil"
"os"
"path"
"runtime"
"strings"
"time"
)
var cmdRouter = &Command{
UsageLine: "router",
Short: "auto-generate routers for the app controllers",
Long: `
`,
}
func init() {
cmdRouter.Run = autoRouter
}
func autoRouter(cmd *Command, args []string) int {
fmt.Println("[INFO] Starting auto-generating routers...")
return 0
}
// getControllerInfo returns controllers that embeded "beego.controller"
// and their methods of package in given path.
func getControllerInfo(path string) (map[string][]string, error) {
now := time.Now()
path = strings.TrimSuffix(path, "/")
dir, err := os.Open(path)
if err != nil {
return nil, err
}
fis, err := dir.Readdir(0)
if err != nil {
return nil, err
}
files := make([]*source, 0, len(fis))
for _, fi := range fis {
// Only load Go files
if strings.HasSuffix(fi.Name(), ".go") {
f, err := os.Open(path + "/" + fi.Name())
if err != nil {
return nil, err
}
p := make([]byte, fi.Size())
_, err = f.Read(p)
if err != nil {
return nil, err
}
f.Close()
files = append(files, &source{
name: path + "/" + fi.Name(),
data: p,
})
}
}
rw := &routerWalker{
pdoc: &Package{
ImportPath: path,
},
}
cm := make(map[string][]string)
pdoc, err := rw.build(files)
for _, t := range pdoc.Types {
// Check if embeded "beego.Controller".
if strings.Index(t.Decl, "beego.Controller") > -1 {
for _, f := range t.Methods {
cm[t.Name] = append(cm[t.Name], f.Name)
}
}
}
fmt.Println(time.Since(now))
return cm, nil
}
// source represents a source code file.
type source struct {
name string
data []byte
}
func (s *source) Name() string { return s.name }
func (s *source) Size() int64 { return int64(len(s.data)) }
func (s *source) Mode() os.FileMode { return 0 }
func (s *source) ModTime() time.Time { return time.Time{} }
func (s *source) IsDir() bool { return false }
func (s *source) Sys() interface{} { return nil }
// routerWalker holds the state used when building the documentation.
type routerWalker struct {
pdoc *Package
srcs map[string]*source // Source files
fset *token.FileSet
buf []byte // scratch space for printNode method
}
// Package represents full information and documentation for a package.
type Package struct {
ImportPath string
Types []*Type // Top-level declarations
}
// Type represents structs and interfaces.
type Type struct {
Name string // Type name
Decl string
Methods []*Func // Exported methods
}
// Func represents functions
type Func struct {
Name string
}
// build generates data from source files.
func (w *routerWalker) build(srcs []*source) (*Package, error) {
// Add source files to walker, I skipped references here
w.srcs = make(map[string]*source)
for _, src := range srcs {
w.srcs[src.name] = src
}
w.fset = token.NewFileSet()
// Find the package and associated files
ctxt := gobuild.Context{
GOOS: runtime.GOOS,
GOARCH: runtime.GOARCH,
CgoEnabled: true,
JoinPath: path.Join,
IsAbsPath: path.IsAbs,
SplitPathList: func(list string) []string { return strings.Split(list, ":") },
IsDir: func(path string) bool { panic("unexpected") },
HasSubdir: func(root, dir string) (rel string, ok bool) { panic("unexpected") },
ReadDir: func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) },
OpenFile: func(path string) (r io.ReadCloser, err error) { return w.openFile(path) },
Compiler: "gc",
}
bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0)
// Continue if there are no Go source files; we still want the directory info
_, nogo := err.(*gobuild.NoGoError)
if err != nil {
if nogo {
err = nil
} else {
return nil, errors.New("routerWalker.build -> " + err.Error())
}
}
// Parse the Go files
files := make(map[string]*ast.File)
for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) {
file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
if err != nil {
return nil, errors.New("routerWalker.build -> parse go files: " + err.Error())
}
files[name] = file
}
apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil)
mode := doc.Mode(0)
if w.pdoc.ImportPath == "builtin" {
mode |= doc.AllDecls
}
pdoc := doc.New(apkg, w.pdoc.ImportPath, mode)
w.pdoc.Types = w.types(pdoc.Types)
return w.pdoc, err
}
func (w *routerWalker) funcs(fdocs []*doc.Func) []*Func {
var result []*Func
for _, d := range fdocs {
result = append(result, &Func{
Name: d.Name,
})
}
return result
}
func (w *routerWalker) types(tdocs []*doc.Type) []*Type {
var result []*Type
for _, d := range tdocs {
result = append(result, &Type{
Decl: w.printDecl(d.Decl),
Name: d.Name,
Methods: w.funcs(d.Methods),
})
}
return result
}
func (w *routerWalker) printDecl(decl ast.Node) string {
var d Code
d, w.buf = printDecl(decl, w.fset, w.buf)
return d.Text
}
func (w *routerWalker) readDir(dir string) ([]os.FileInfo, error) {
if dir != w.pdoc.ImportPath {
panic("unexpected")
}
fis := make([]os.FileInfo, 0, len(w.srcs))
for _, src := range w.srcs {
fis = append(fis, src)
}
return fis, nil
}
func (w *routerWalker) openFile(path string) (io.ReadCloser, error) {
if strings.HasPrefix(path, w.pdoc.ImportPath+"/") {
if src, ok := w.srcs[path[len(w.pdoc.ImportPath)+1:]]; ok {
return ioutil.NopCloser(bytes.NewReader(src.data)), nil
}
}
panic("unexpected")
}
func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
pkg := imports[path]
if pkg == nil {
// Guess the package name without importing it. Start with the last
// element of the path.
name := path[strings.LastIndex(path, "/")+1:]
// Trim commonly used prefixes and suffixes containing illegal name
// runes.
name = strings.TrimSuffix(name, ".go")
name = strings.TrimSuffix(name, "-go")
name = strings.TrimPrefix(name, "go.")
name = strings.TrimPrefix(name, "go-")
name = strings.TrimPrefix(name, "biogo.")
// It's also common for the last element of the path to contain an
// extra "go" prefix, but not always.
// TODO: examine unresolved ids to detect when trimming the "go" prefix is appropriate.
pkg = ast.NewObj(ast.Pkg, name)
pkg.Data = ast.NewScope(nil)
imports[path] = pkg
}
return pkg, nil
}

View File

@ -1,9 +0,0 @@
package main
import (
"testing"
)
func TestGetControllerInfo(t *testing.T) {
getControllerInfo("testdata/router/")
}

258
bee.go
View File

@ -1,258 +0,0 @@
// 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.
// Bee is a tool for developing applications based on beego framework.
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"strings"
"text/template"
)
const version = "1.8.0"
// Command is the unit of execution
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string) int
// PreRun performs an operation before running the command
PreRun func(cmd *Command, args []string)
// UsageLine is the one-line usage message.
// The first word in the line is taken to be the command name.
UsageLine string
// Short is the short description shown in the 'go help' output.
Short string
// Long is the long message shown in the 'go help <this-command>' output.
Long string
// Flag is a set of flags specific to this command.
Flag flag.FlagSet
// CustomFlags indicates that the command will do its own
// flag parsing.
CustomFlags bool
// output out writer if set in SetOutput(w)
output *io.Writer
}
// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
name := c.UsageLine
i := strings.Index(name, " ")
if i >= 0 {
name = name[:i]
}
return name
}
// SetOutput sets the destination for usage and error messages.
// If output is nil, os.Stderr is used.
func (c *Command) SetOutput(output io.Writer) {
c.output = &output
}
// Out returns the out writer of the current command.
// If cmd.output is nil, os.Stderr is used.
func (c *Command) Out() io.Writer {
if c.output != nil {
return *c.output
}
return NewColorWriter(os.Stderr)
}
// Usage puts out the usage for the command.
func (c *Command) Usage() {
tmpl(cmdUsage, c)
os.Exit(2)
}
// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as import path.
func (c *Command) Runnable() bool {
return c.Run != nil
}
func (c *Command) Options() map[string]string {
options := make(map[string]string)
c.Flag.VisitAll(func(f *flag.Flag) {
defaultVal := f.DefValue
if len(defaultVal) > 0 {
options[f.Name+"="+defaultVal] = f.Usage
} else {
options[f.Name] = f.Usage
}
})
return options
}
var availableCommands = []*Command{
cmdNew,
cmdRun,
cmdPack,
cmdApiapp,
cmdHproseapp,
//cmdRouter,
//cmdTest,
cmdBale,
cmdVersion,
cmdGenerate,
//cmdRundocs,
cmdMigrate,
cmdFix,
cmdDockerize,
}
var logger = GetBeeLogger(os.Stdout)
func main() {
currentpath, _ := os.Getwd()
flag.Usage = usage
flag.Parse()
log.SetFlags(0)
args := flag.Args()
if len(args) < 1 {
usage()
}
if args[0] == "help" {
help(args[1:])
return
}
for _, cmd := range availableCommands {
if cmd.Name() == args[0] && cmd.Run != nil {
cmd.Flag.Usage = func() { cmd.Usage() }
if cmd.CustomFlags {
args = args[1:]
} else {
cmd.Flag.Parse(args[1:])
args = cmd.Flag.Args()
}
if cmd.PreRun != nil {
cmd.PreRun(cmd, args)
}
// Check if current directory is inside the GOPATH,
// if so parse the packages inside it.
if strings.Contains(currentpath, GetGOPATHs()[0]+"/src") && isGenerateDocs(cmd.Name(), args) {
parsePackagesFromDir(currentpath)
}
os.Exit(cmd.Run(cmd, args))
return
}
}
printErrorAndExit("Unknown subcommand")
}
func isGenerateDocs(name string, args []string) bool {
if name != "generate" {
return false
}
for _, a := range args {
if a == "docs" {
return true
}
}
return false
}
var usageTemplate = `Bee is a Fast and Flexible tool for managing your Beego Web Application.
{{"USAGE" | headline}}
{{"bee command [arguments]" | bold}}
{{"AVAILABLE COMMANDS" | headline}}
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s" | bold}} {{.Short}}{{end}}{{end}}
Use {{"bee help [command]" | bold}} for more information about a command.
{{"ADDITIONAL HELP TOPICS" | headline}}
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use {{"bee help [topic]" | bold}} for more information about that topic.
`
var helpTemplate = `{{"USAGE" | headline}}
{{.UsageLine | printf "bee %s" | bold}}
{{if .Options}}{{endline}}{{"OPTIONS" | headline}}{{range $k,$v := .Options}}
{{$k | printf "-%s" | bold}}
{{$v}}
{{end}}{{end}}
{{"DESCRIPTION" | headline}}
{{tmpltostr .Long . | trim}}
`
var errorTemplate = `bee: %s.
Use {{"bee help" | bold}} for more information.
`
var cmdUsage = `Use {{printf "bee help %s" .Name | bold}} for more information.{{endline}}`
func usage() {
tmpl(usageTemplate, availableCommands)
os.Exit(2)
}
func tmpl(text string, data interface{}) {
output := NewColorWriter(os.Stderr)
t := template.New("usage").Funcs(BeeFuncMap())
template.Must(t.Parse(text))
err := t.Execute(output, data)
MustCheck(err)
}
func help(args []string) {
if len(args) == 0 {
usage()
}
if len(args) != 1 {
printErrorAndExit("Too many arguments")
}
arg := args[0]
for _, cmd := range availableCommands {
if cmd.Name() == arg {
tmpl(helpTemplate, cmd)
return
}
}
printErrorAndExit("Unknown help topic")
}
func printErrorAndExit(message string) {
tmpl(fmt.Sprintf(errorTemplate, message), nil)
os.Exit(2)
}

102
cmd/bee.go Normal file
View File

@ -0,0 +1,102 @@
// 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.
// Bee is a tool for developing applications based on beego framework.
package cmd
import (
"os"
"github.com/beego/bee/cmd/commands"
_ "github.com/beego/bee/cmd/commands/api"
_ "github.com/beego/bee/cmd/commands/bale"
_ "github.com/beego/bee/cmd/commands/beefix"
_ "github.com/beego/bee/cmd/commands/dockerize"
_ "github.com/beego/bee/cmd/commands/generate"
_ "github.com/beego/bee/cmd/commands/hprose"
_ "github.com/beego/bee/cmd/commands/migrate"
_ "github.com/beego/bee/cmd/commands/new"
_ "github.com/beego/bee/cmd/commands/pack"
_ "github.com/beego/bee/cmd/commands/run"
_ "github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/utils"
)
func IfGenerateDocs(name string, args []string) bool {
if name != "generate" {
return false
}
for _, a := range args {
if a == "docs" {
return true
}
}
return false
}
var usageTemplate = `Bee is a Fast and Flexible tool for managing your Beego Web Application.
{{"USAGE" | headline}}
{{"bee command [arguments]" | bold}}
{{"AVAILABLE COMMANDS" | headline}}
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s" | bold}} {{.Short}}{{end}}{{end}}
Use {{"bee help [command]" | bold}} for more information about a command.
{{"ADDITIONAL HELP TOPICS" | headline}}
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use {{"bee help [topic]" | bold}} for more information about that topic.
`
var helpTemplate = `{{"USAGE" | headline}}
{{.UsageLine | printf "bee %s" | bold}}
{{if .Options}}{{endline}}{{"OPTIONS" | headline}}{{range $k,$v := .Options}}
{{$k | printf "-%s" | bold}}
{{$v}}
{{end}}{{end}}
{{"DESCRIPTION" | headline}}
{{tmpltostr .Long . | trim}}
`
var ErrorTemplate = `bee: %s.
Use {{"bee help" | bold}} for more information.
`
func Usage() {
utils.Tmpl(usageTemplate, commands.AvailableCommands)
os.Exit(2)
}
func Help(args []string) {
if len(args) == 0 {
Usage()
}
if len(args) != 1 {
utils.PrintErrorAndExit("Too many arguments", ErrorTemplate)
}
arg := args[0]
for _, cmd := range commands.AvailableCommands {
if cmd.Name() == arg {
utils.Tmpl(helpTemplate, cmd)
return
}
}
utils.PrintErrorAndExit("Unknown help topic", ErrorTemplate)
}

View File

@ -12,16 +12,22 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package apiapp
import (
"fmt"
"os"
path "path/filepath"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/generate"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
)
var cmdApiapp = &Command{
var CmdApiapp = &commands.Command{
// CustomFlags: true,
UsageLine: "api [appname]",
Short: "Creates a Beego API application",
@ -50,10 +56,9 @@ var cmdApiapp = &Command{
object.go
user.go
`,
PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() },
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: createapi,
}
var apiconf = `appname = {{.Appname}}
httpport = 8080
runmode = dev
@ -134,7 +139,7 @@ func init() {
}
`
var apiModels = `package models
var ApiModels = `package models
import (
"errors"
@ -189,7 +194,7 @@ func Delete(ObjectId string) {
`
var apiModels2 = `package models
var ApiModels2 = `package models
import (
"errors"
@ -532,33 +537,32 @@ func TestGet(t *testing.T) {
`
func init() {
cmdApiapp.Flag.Var(&tables, "tables", "List of table names separated by a comma.")
cmdApiapp.Flag.Var(&driver, "driver", "Database driver. Either mysql, postgres or sqlite.")
cmdApiapp.Flag.Var(&conn, "conn", "Connection string used by the driver to connect to a database instance.")
CmdApiapp.Flag.Var(&generate.Tables, "tables", "List of table names separated by a comma.")
CmdApiapp.Flag.Var(&generate.SQLDriver, "driver", "Database driver. Either mysql, postgres or sqlite.")
CmdApiapp.Flag.Var(&generate.SQLConn, "conn", "Connection string used by the driver to connect to a database instance.")
commands.AvailableCommands = append(commands.AvailableCommands, CmdApiapp)
}
func createapi(cmd *Command, args []string) int {
func createapi(cmd *commands.Command, args []string) int {
output := cmd.Out()
if len(args) < 1 {
logger.Fatal("Argument [appname] is missing")
beeLogger.Log.Fatal("Argument [appname] is missing")
}
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
}
apppath, packpath, err := checkEnv(args[0])
apppath, packpath, err := utils.CheckEnv(args[0])
if err != nil {
logger.Fatalf("%s", err)
beeLogger.Log.Fatalf("%s", err)
}
if driver == "" {
driver = "mysql"
}
if conn == "" {
if generate.SQLDriver == "" {
generate.SQLDriver = "mysql"
}
logger.Info("Creating API...")
beeLogger.Log.Info("Creating API...")
os.MkdirAll(apppath, 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath, "\x1b[0m")
@ -569,30 +573,30 @@ func createapi(cmd *Command, args []string) int {
os.Mkdir(path.Join(apppath, "tests"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests"), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m")
WriteToFile(path.Join(apppath, "conf", "app.conf"),
utils.WriteToFile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(apiconf, "{{.Appname}}", path.Base(args[0]), -1))
if conn != "" {
if generate.SQLConn != "" {
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
maingoContent := strings.Replace(apiMainconngo, "{{.Appname}}", packpath, -1)
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1)
if driver == "mysql" {
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(generate.SQLDriver), -1)
if generate.SQLDriver == "mysql" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1)
} else if driver == "postgres" {
} else if generate.SQLDriver == "postgres" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1)
}
WriteToFile(path.Join(apppath, "main.go"),
utils.WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(
maingoContent,
"{{.conn}}",
conn.String(),
generate.SQLConn.String(),
-1,
),
)
logger.Infof("Using '%s' as 'driver'", driver)
logger.Infof("Using '%s' as 'conn'", conn)
logger.Infof("Using '%s' as 'tables'", tables)
generateAppcode(string(driver), string(conn), "3", string(tables), apppath)
beeLogger.Log.Infof("Using '%s' as 'driver'", generate.SQLDriver)
beeLogger.Log.Infof("Using '%s' as 'conn'", generate.SQLConn)
beeLogger.Log.Infof("Using '%s' as 'tables'", generate.Tables)
generate.GenerateAppcode(string(generate.SQLDriver), string(generate.SQLConn), "3", string(generate.Tables), apppath)
} else {
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m")
@ -600,65 +604,31 @@ func createapi(cmd *Command, args []string) int {
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers")+string(path.Separator), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "object.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "controllers", "object.go"),
utils.WriteToFile(path.Join(apppath, "controllers", "object.go"),
strings.Replace(apiControllers, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "user.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "controllers", "user.go"),
utils.WriteToFile(path.Join(apppath, "controllers", "user.go"),
strings.Replace(apiControllers2, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests", "default_test.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "tests", "default_test.go"),
utils.WriteToFile(path.Join(apppath, "tests", "default_test.go"),
strings.Replace(apiTests, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers", "router.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "routers", "router.go"),
utils.WriteToFile(path.Join(apppath, "routers", "router.go"),
strings.Replace(apirouter, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "object.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "models", "object.go"), apiModels)
utils.WriteToFile(path.Join(apppath, "models", "object.go"), ApiModels)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "models", "user.go"), apiModels2)
utils.WriteToFile(path.Join(apppath, "models", "user.go"), ApiModels2)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "main.go"),
utils.WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1))
}
logger.Success("New API successfully created!")
beeLogger.Log.Success("New API successfully created!")
return 0
}
func checkEnv(appname string) (apppath, packpath string, err error) {
gps := GetGOPATHs()
if len(gps) == 0 {
logger.Fatal("GOPATH environment variable is not set or empty")
}
currpath, _ := os.Getwd()
currpath = path.Join(currpath, appname)
for _, gpath := range gps {
gsrcpath := path.Join(gpath, "src")
if strings.HasPrefix(currpath, gsrcpath) {
packpath = strings.Replace(currpath[len(gsrcpath)+1:], string(path.Separator), "/", -1)
return currpath, packpath, nil
}
}
// In case of multiple paths in the GOPATH, by default
// we use the first path
gopath := gps[0]
logger.Warn("You current workdir is not inside $GOPATH/src.")
logger.Debugf("GOPATH: %s", __FILE__(), __LINE__(), gopath)
gosrcpath := path.Join(gopath, "src")
apppath = path.Join(gosrcpath, appname)
if _, e := os.Stat(apppath); os.IsNotExist(e) == false {
err = fmt.Errorf("Cannot create application without removing '%s' first.", apppath)
logger.Errorf("Path '%s' already exists", apppath)
return
}
packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/")
return
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package bale
import (
"bytes"
@ -24,9 +24,15 @@ import (
"path/filepath"
"runtime"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/config"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
)
var cmdBale = &Command{
var CmdBale = &commands.Command{
UsageLine: "bale",
Short: "Transforms non-Go files to Go source files",
Long: `Bale command compress all the static files in to a single binary file.
@ -37,47 +43,46 @@ var cmdBale = &Command{
It will auto-generate an unpack function to the main package then run it during the runtime.
This is mainly used for zealots who are requiring 100% Go code.
`,
PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() },
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: runBale,
}
func runBale(cmd *Command, args []string) int {
err := loadConfig()
if err != nil {
logger.Fatalf("Failed to load configuration: %s", err)
}
func init() {
commands.AvailableCommands = append(commands.AvailableCommands, CmdBale)
}
func runBale(cmd *commands.Command, args []string) int {
os.RemoveAll("bale")
os.Mkdir("bale", os.ModePerm)
// Pack and compress data
for _, p := range conf.Bale.Dirs {
if !isExist(p) {
logger.Warnf("Skipped directory: %s", p)
for _, p := range config.Conf.Bale.Dirs {
if !utils.IsExist(p) {
beeLogger.Log.Warnf("Skipped directory: %s", p)
continue
}
logger.Infof("Packaging directory: %s", p)
beeLogger.Log.Infof("Packaging directory: %s", p)
filepath.Walk(p, walkFn)
}
// Generate auto-uncompress function.
buf := new(bytes.Buffer)
buf.WriteString(fmt.Sprintf(BaleHeader, conf.Bale.Import,
buf.WriteString(fmt.Sprintf(BaleHeader, config.Conf.Bale.Import,
strings.Join(resFiles, "\",\n\t\t\""),
strings.Join(resFiles, ",\n\t\tbale.R")))
fw, err := os.Create("bale.go")
if err != nil {
logger.Fatalf("Failed to create file: %s", err)
beeLogger.Log.Fatalf("Failed to create file: %s", err)
}
defer fw.Close()
_, err = fw.Write(buf.Bytes())
if err != nil {
logger.Fatalf("Failed to write data: %s", err)
beeLogger.Log.Fatalf("Failed to write data: %s", err)
}
logger.Success("Baled resources successfully!")
beeLogger.Log.Success("Baled resources successfully!")
return 0
}
@ -146,7 +151,7 @@ func walkFn(resPath string, info os.FileInfo, err error) error {
// Open resource files
fr, err := os.Open(resPath)
if err != nil {
logger.Fatalf("Failed to read file: %s", err)
beeLogger.Log.Fatalf("Failed to read file: %s", err)
}
// Convert path
@ -164,7 +169,7 @@ func walkFn(resPath string, info os.FileInfo, err error) error {
os.MkdirAll(path.Dir(resPath), os.ModePerm)
fw, err := os.Create("bale/" + resPath + ".go")
if err != nil {
logger.Fatalf("Failed to create file: %s", err)
beeLogger.Log.Fatalf("Failed to create file: %s", err)
}
defer fw.Close()
@ -184,7 +189,7 @@ func walkFn(resPath string, info os.FileInfo, err error) error {
}
func filterSuffix(name string) bool {
for _, s := range conf.Bale.IngExt {
for _, s := range config.Conf.Bale.IngExt {
if strings.HasSuffix(name, s) {
return true
}

View File

@ -1,4 +1,4 @@
package main
package beefix
import (
"fmt"
@ -9,9 +9,14 @@ import (
"path/filepath"
"regexp"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
)
var cmdFix = &Command{
var CmdFix = &commands.Command{
UsageLine: "fix",
Short: "Fixes your application by making it compatible with newer versions of Beego",
Long: `As of {{"Beego 1.6"|bold}}, there are some backward compatibility issues.
@ -22,18 +27,19 @@ var cmdFix = &Command{
}
func init() {
cmdFix.Run = runFix
cmdFix.PreRun = func(cmd *Command, args []string) { ShowShortVersionBanner() }
CmdFix.Run = runFix
CmdFix.PreRun = func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }
commands.AvailableCommands = append(commands.AvailableCommands, CmdFix)
}
func runFix(cmd *Command, args []string) int {
func runFix(cmd *commands.Command, args []string) int {
output := cmd.Out()
logger.Info("Upgrading the application...")
beeLogger.Log.Info("Upgrading the application...")
dir, err := os.Getwd()
if err != nil {
logger.Fatalf("Error while getting the current working directory: %s", err)
beeLogger.Log.Fatalf("Error while getting the current working directory: %s", err)
}
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
@ -50,13 +56,13 @@ func runFix(cmd *Command, args []string) int {
return nil
}
err = fixFile(path)
fmt.Fprintf(output, GreenBold("\tfix\t")+"%s\n", path)
fmt.Fprintf(output, colors.GreenBold("\tfix\t")+"%s\n", path)
if err != nil {
logger.Errorf("Could not fix file: %s", err)
beeLogger.Log.Errorf("Could not fix file: %s", err)
}
return err
})
logger.Success("Upgrade Done!")
beeLogger.Log.Success("Upgrade Done!")
return 0
}

94
cmd/commands/command.go Normal file
View File

@ -0,0 +1,94 @@
package commands
import (
"flag"
"io"
"os"
"strings"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
)
// Command is the unit of execution
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string) int
// PreRun performs an operation before running the command
PreRun func(cmd *Command, args []string)
// UsageLine is the one-line Usage message.
// The first word in the line is taken to be the command name.
UsageLine string
// Short is the short description shown in the 'go help' output.
Short string
// Long is the long message shown in the 'go help <this-command>' output.
Long string
// Flag is a set of flags specific to this command.
Flag flag.FlagSet
// CustomFlags indicates that the command will do its own
// flag parsing.
CustomFlags bool
// output out writer if set in SetOutput(w)
output *io.Writer
}
var AvailableCommands = []*Command{}
var cmdUsage = `Use {{printf "bee help %s" .Name | bold}} for more information.{{endline}}`
// Name returns the command's name: the first word in the Usage line.
func (c *Command) Name() string {
name := c.UsageLine
i := strings.Index(name, " ")
if i >= 0 {
name = name[:i]
}
return name
}
// SetOutput sets the destination for Usage and error messages.
// If output is nil, os.Stderr is used.
func (c *Command) SetOutput(output io.Writer) {
c.output = &output
}
// Out returns the out writer of the current command.
// If cmd.output is nil, os.Stderr is used.
func (c *Command) Out() io.Writer {
if c.output != nil {
return *c.output
}
return colors.NewColorWriter(os.Stderr)
}
// Usage puts out the Usage for the command.
func (c *Command) Usage() {
utils.Tmpl(cmdUsage, c)
os.Exit(2)
}
// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as import path.
func (c *Command) Runnable() bool {
return c.Run != nil
}
func (c *Command) Options() map[string]string {
options := make(map[string]string)
c.Flag.VisitAll(func(f *flag.Flag) {
defaultVal := f.DefValue
if len(defaultVal) > 0 {
options[f.Name+"="+defaultVal] = f.Usage
} else {
options[f.Name] = f.Usage
}
})
return options
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package dockerize
import (
"flag"
@ -21,22 +21,13 @@ import (
"path/filepath"
"strings"
"text/template"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
)
var cmdDockerize = &Command{
CustomFlags: true,
UsageLine: "dockerize",
Short: "Generates a Dockerfile for your Beego application",
Long: `Dockerize generates a Dockerfile for your Beego Web Application.
The Dockerfile will compile, get the dependencies with {{"godep"|bold}}, and set the entrypoint.
{{"Example:"|bold}}
$ bee dockerize -expose="3000,80,25"
`,
PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() },
Run: dockerizeApp,
}
const dockerBuildTemplate = `FROM {{.BaseImage}}
# Godep for vendoring
@ -67,6 +58,20 @@ type Dockerfile struct {
Expose string
}
var CmdDockerize = &commands.Command{
CustomFlags: true,
UsageLine: "dockerize",
Short: "Generates a Dockerfile for your Beego application",
Long: `Dockerize generates a Dockerfile for your Beego Web Application.
The Dockerfile will compile, get the dependencies with {{"godep"|bold}}, and set the entrypoint.
{{"Example:"|bold}}
$ bee dockerize -expose="3000,80,25"
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: dockerizeApp,
}
var (
expose string
baseImage string
@ -76,19 +81,22 @@ func init() {
fs := flag.NewFlagSet("dockerize", flag.ContinueOnError)
fs.StringVar(&baseImage, "image", "library/golang", "Set the base image of the Docker container.")
fs.StringVar(&expose, "expose", "8080", "Port(s) to expose in the Docker container.")
cmdDockerize.Flag = *fs
CmdDockerize.Flag = *fs
commands.AvailableCommands = append(commands.AvailableCommands, CmdDockerize)
}
func dockerizeApp(cmd *Command, args []string) int {
func dockerizeApp(cmd *commands.Command, args []string) int {
if err := cmd.Flag.Parse(args); err != nil {
logger.Fatalf("Error parsing flags: %v", err.Error())
beeLogger.Log.Fatalf("Error parsing flags: %v", err.Error())
}
logger.Info("Generating Dockerfile...")
beeLogger.Log.Info("Generating Dockerfile...")
gopath := os.Getenv("GOPATH")
dir, err := filepath.Abs(".")
MustCheck(err)
if err != nil {
beeLogger.Log.Error(err.Error())
}
appdir := strings.Replace(dir, gopath, "", 1)
@ -112,15 +120,15 @@ func dockerizeApp(cmd *Command, args []string) int {
}
func generateDockerfile(df Dockerfile) {
t := template.Must(template.New("dockerBuildTemplate").Parse(dockerBuildTemplate)).Funcs(BeeFuncMap())
t := template.Must(template.New("dockerBuildTemplate").Parse(dockerBuildTemplate)).Funcs(utils.BeeFuncMap())
f, err := os.Create("Dockerfile")
if err != nil {
logger.Fatalf("Error writing Dockerfile: %v", err.Error())
beeLogger.Log.Fatalf("Error writing Dockerfile: %v", err.Error())
}
defer CloseFile(f)
defer utils.CloseFile(f)
t.Execute(f, df)
logger.Success("Dockerfile generated.")
beeLogger.Log.Success("Dockerfile generated.")
}

View File

@ -0,0 +1,203 @@
package generate
import (
"os"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/config"
"github.com/beego/bee/generate"
"github.com/beego/bee/generate/swaggergen"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
)
var CmdGenerate = &commands.Command{
UsageLine: "generate [command]",
Short: "Source code generator",
Long: ` {{"To scaffold out your entire application:"|bold}}
$ bee generate scaffold [scaffoldname] [-fields="title:string,body:text"] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]
{{"To generate a Model based on fields:"|bold}}
$ bee generate model [modelname] [-fields="name:type"]
{{"To generate a controller:"|bold}}
$ bee generate controller [controllerfile]
{{"To generate a CRUD view:"|bold}}
$ bee generate view [viewpath]
{{"To generate a migration file for making database schema updates:"|bold}}
$ bee generate migration [migrationfile] [-fields="name:type"]
{{"To generate swagger doc file:"|bold}}
$ bee generate docs
{{"To generate a test case:"|bold}}
$ bee generate test [routerfile]
{{"To generate appcode based on an existing database:"|bold}}
$ bee generate appcode [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-level=3]
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: GenerateCode,
}
func init() {
CmdGenerate.Flag.Var(&generate.Tables, "Tables", "List of table names separated by a comma.")
CmdGenerate.Flag.Var(&generate.SQLDriver, "SQLDriver", "Database SQLDriver. Either mysql, postgres or sqlite.")
CmdGenerate.Flag.Var(&generate.SQLConn, "SQLConn", "Connection string used by the SQLDriver to connect to a database instance.")
CmdGenerate.Flag.Var(&generate.Level, "Level", "Either 1, 2 or 3. i.e. 1=models; 2=models and controllers; 3=models, controllers and routers.")
CmdGenerate.Flag.Var(&generate.Fields, "Fields", "List of table Fields.")
commands.AvailableCommands = append(commands.AvailableCommands, CmdGenerate)
}
func GenerateCode(cmd *commands.Command, args []string) int {
currpath, _ := os.Getwd()
if len(args) < 1 {
beeLogger.Log.Fatal("Command is missing")
}
gps := utils.GetGOPATHs()
if len(gps) == 0 {
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
gopath := gps[0]
beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath)
gcmd := args[0]
switch gcmd {
case "scaffold":
scaffold(cmd, args, currpath)
case "docs":
swaggergen.GenerateDocs(currpath)
case "appcode":
appCode(cmd, args, currpath)
case "migration":
migration(cmd, args, currpath)
case "controller":
controller(args, currpath)
case "model":
model(cmd, args, currpath)
case "view":
view(args, currpath)
default:
beeLogger.Log.Fatal("Command is missing")
}
beeLogger.Log.Successf("%s successfully generated!", strings.Title(gcmd))
return 0
}
func scaffold(cmd *commands.Command, args []string, currpath string) {
if len(args) < 2 {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
cmd.Flag.Parse(args[2:])
if generate.SQLDriver == "" {
generate.SQLDriver = utils.DocValue(config.Conf.Database.Driver)
if generate.SQLDriver == "" {
generate.SQLDriver = "mysql"
}
}
if generate.SQLConn == "" {
generate.SQLConn = utils.DocValue(config.Conf.Database.Conn)
if generate.SQLConn == "" {
generate.SQLConn = "root:@tcp(127.0.0.1:3306)/test"
}
}
if generate.Fields == "" {
beeLogger.Log.Hint("Fields option should not be empty, i.e. -Fields=\"title:string,body:text\"")
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
sname := args[1]
generate.GenerateScaffold(sname, generate.Fields.String(), currpath, generate.SQLDriver.String(), generate.SQLConn.String())
}
func appCode(cmd *commands.Command, args []string, currpath string) {
cmd.Flag.Parse(args[1:])
if generate.SQLDriver == "" {
generate.SQLDriver = utils.DocValue(config.Conf.Database.Driver)
if generate.SQLDriver == "" {
generate.SQLDriver = "mysql"
}
}
if generate.SQLConn == "" {
generate.SQLConn = utils.DocValue(config.Conf.Database.Conn)
if generate.SQLConn == "" {
if generate.SQLDriver == "mysql" {
generate.SQLConn = "root:@tcp(127.0.0.1:3306)/test"
} else if generate.SQLDriver == "postgres" {
generate.SQLConn = "postgres://postgres:postgres@127.0.0.1:5432/postgres"
}
}
}
if generate.Level == "" {
generate.Level = "3"
}
beeLogger.Log.Infof("Using '%s' as 'SQLDriver'", generate.SQLDriver)
beeLogger.Log.Infof("Using '%s' as 'SQLConn'", generate.SQLConn)
beeLogger.Log.Infof("Using '%s' as 'Tables'", generate.Tables)
beeLogger.Log.Infof("Using '%s' as 'Level'", generate.Level)
generate.GenerateAppcode(generate.SQLDriver.String(), generate.SQLConn.String(), generate.Level.String(), generate.Tables.String(), currpath)
}
func migration(cmd *commands.Command, args []string, currpath string) {
if len(args) < 2 {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
cmd.Flag.Parse(args[2:])
mname := args[1]
beeLogger.Log.Infof("Using '%s' as migration name", mname)
upsql := ""
downsql := ""
if generate.Fields != "" {
dbMigrator := generate.NewDBDriver()
upsql = dbMigrator.GenerateCreateUp(mname)
downsql = dbMigrator.GenerateCreateDown(mname)
}
generate.GenerateMigration(mname, upsql, downsql, currpath)
}
func controller(args []string, currpath string) {
if len(args) == 2 {
cname := args[1]
generate.GenerateController(cname, currpath)
} else {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
}
func model(cmd *commands.Command, args []string, currpath string) {
if len(args) < 2 {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
cmd.Flag.Parse(args[2:])
if generate.Fields == "" {
beeLogger.Log.Hint("Fields option should not be empty, i.e. -Fields=\"title:string,body:text\"")
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
sname := args[1]
generate.GenerateModel(sname, generate.Fields.String(), currpath)
}
func view(args []string, currpath string) {
if len(args) == 2 {
cname := args[1]
generate.GenerateView(cname, currpath)
} else {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
}

View File

@ -0,0 +1,119 @@
package hprose
import (
"os"
"fmt"
"path"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/api"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/generate"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
)
var CmdHproseapp = &commands.Command{
// CustomFlags: true,
UsageLine: "hprose [appname]",
Short: "Creates an RPC application based on Hprose and Beego frameworks",
Long: `
The command 'hprose' creates an RPC application based on both Beego and Hprose (http://hprose.com/).
{{"To scaffold out your application, use:"|bold}}
$ bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test]
If 'conn' is empty, the command will generate a sample application. Otherwise the command
will connect to your database and generate models based on the existing tables.
The command 'hprose' creates a folder named [appname] with the following structure:
main.go
{{"conf"|foldername}}
app.conf
{{"models"|foldername}}
object.go
user.go
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: createhprose,
}
func init() {
CmdHproseapp.Flag.Var(&generate.Tables, "tables", "List of table names separated by a comma.")
CmdHproseapp.Flag.Var(&generate.SQLDriver, "driver", "Database driver. Either mysql, postgres or sqlite.")
CmdHproseapp.Flag.Var(&generate.SQLConn, "conn", "Connection string used by the driver to connect to a database instance.")
commands.AvailableCommands = append(commands.AvailableCommands, CmdHproseapp)
}
func createhprose(cmd *commands.Command, args []string) int {
output := cmd.Out()
if len(args) != 1 {
beeLogger.Log.Fatal("Argument [appname] is missing")
}
curpath, _ := os.Getwd()
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
}
apppath, packpath, err := utils.CheckEnv(args[0])
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
if generate.SQLDriver == "" {
generate.SQLDriver = "mysql"
}
beeLogger.Log.Info("Creating Hprose application...")
os.MkdirAll(apppath, 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath, "\x1b[0m")
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(generate.Hproseconf, "{{.Appname}}", args[0], -1))
if generate.SQLConn != "" {
beeLogger.Log.Infof("Using '%s' as 'driver'", generate.SQLDriver)
beeLogger.Log.Infof("Using '%s' as 'conn'", generate.SQLConn)
beeLogger.Log.Infof("Using '%s' as 'tables'", generate.Tables)
generate.GenerateHproseAppcode(string(generate.SQLDriver), string(generate.SQLConn), "1", string(generate.Tables), path.Join(curpath, args[0]))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
maingoContent := strings.Replace(generate.HproseMainconngo, "{{.Appname}}", packpath, -1)
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(generate.SQLDriver), -1)
maingoContent = strings.Replace(maingoContent, "{{HproseFunctionList}}", strings.Join(generate.HproseAddFunctions, ""), -1)
if generate.SQLDriver == "mysql" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1)
} else if generate.SQLDriver == "postgres" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1)
}
utils.WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(
maingoContent,
"{{.conn}}",
generate.SQLConn.String(),
-1,
),
)
} else {
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "object.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "models", "object.go"), apiapp.ApiModels)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "models", "user.go"), apiapp.ApiModels2)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(generate.HproseMaingo, "{{.Appname}}", packpath, -1))
}
beeLogger.Log.Success("New Hprose application successfully created!")
return 0
}

View File

@ -1,18 +1,4 @@
// 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.
package main
package migrate
import (
"database/sql"
@ -23,9 +9,16 @@ import (
"strconv"
"strings"
"time"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/config"
"github.com/beego/bee/utils"
beeLogger "github.com/beego/bee/logger"
)
var cmdMigrate = &Command{
var CmdMigrate = &commands.Command{
UsageLine: "migrate [Command]",
Short: "Runs database migrations",
Long: `The command 'migrate' allows you to run database migrations to keep it up-to-date.
@ -46,100 +39,75 @@ var cmdMigrate = &Command{
$ bee migrate refresh [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]
`,
PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() },
Run: runMigration,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: RunMigration,
}
var mDriver docValue
var mConn docValue
var mDriver utils.DocValue
var mConn utils.DocValue
func init() {
cmdMigrate.Flag.Var(&mDriver, "driver", "Database driver. Either mysql, postgres or sqlite.")
cmdMigrate.Flag.Var(&mConn, "conn", "Connection string used by the driver to connect to a database instance.")
CmdMigrate.Flag.Var(&mDriver, "driver", "Database driver. Either mysql, postgres or sqlite.")
CmdMigrate.Flag.Var(&mConn, "conn", "Connection string used by the driver to connect to a database instance.")
commands.AvailableCommands = append(commands.AvailableCommands, CmdMigrate)
}
// runMigration is the entry point for starting a migration
func runMigration(cmd *Command, args []string) int {
func RunMigration(cmd *commands.Command, args []string) int {
currpath, _ := os.Getwd()
gps := GetGOPATHs()
gps := utils.GetGOPATHs()
if len(gps) == 0 {
logger.Fatal("GOPATH environment variable is not set or empty")
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
gopath := gps[0]
logger.Debugf("GOPATH: %s", __FILE__(), __LINE__(), gopath)
// Load the configuration
err := loadConfig()
if err != nil {
logger.Errorf("Failed to load configuration: %s", err)
}
beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath)
// Getting command line arguments
if len(args) != 0 {
cmd.Flag.Parse(args[1:])
}
if mDriver == "" {
mDriver = docValue(conf.Database.Driver)
mDriver = utils.DocValue(config.Conf.Database.Driver)
if mDriver == "" {
mDriver = "mysql"
}
}
if mConn == "" {
mConn = docValue(conf.Database.Conn)
mConn = utils.DocValue(config.Conf.Database.Conn)
if mConn == "" {
mConn = "root:@tcp(127.0.0.1:3306)/test"
}
}
logger.Infof("Using '%s' as 'driver'", mDriver)
logger.Infof("Using '%s' as 'conn'", mConn)
beeLogger.Log.Infof("Using '%s' as 'driver'", mDriver)
beeLogger.Log.Infof("Using '%s' as 'conn'", mConn)
driverStr, connStr := string(mDriver), string(mConn)
if len(args) == 0 {
// run all outstanding migrations
logger.Info("Running all outstanding migrations")
migrateUpdate(currpath, driverStr, connStr)
beeLogger.Log.Info("Running all outstanding migrations")
MigrateUpdate(currpath, driverStr, connStr)
} else {
mcmd := args[0]
switch mcmd {
case "rollback":
logger.Info("Rolling back the last migration operation")
migrateRollback(currpath, driverStr, connStr)
beeLogger.Log.Info("Rolling back the last migration operation")
MigrateRollback(currpath, driverStr, connStr)
case "reset":
logger.Info("Reseting all migrations")
migrateReset(currpath, driverStr, connStr)
beeLogger.Log.Info("Reseting all migrations")
MigrateReset(currpath, driverStr, connStr)
case "refresh":
logger.Info("Refreshing all migrations")
migrateRefresh(currpath, driverStr, connStr)
beeLogger.Log.Info("Refreshing all migrations")
MigrateRefresh(currpath, driverStr, connStr)
default:
logger.Fatal("Command is missing")
beeLogger.Log.Fatal("Command is missing")
}
}
logger.Success("Migration successful!")
beeLogger.Log.Success("Migration successful!")
return 0
}
// migrateUpdate does the schema update
func migrateUpdate(currpath, driver, connStr string) {
migrate("upgrade", currpath, driver, connStr)
}
// migrateRollback rolls back the latest migration
func migrateRollback(currpath, driver, connStr string) {
migrate("rollback", currpath, driver, connStr)
}
// migrateReset rolls back all migrations
func migrateReset(currpath, driver, connStr string) {
migrate("reset", currpath, driver, connStr)
}
// migrationRefresh rolls back all migrations and start over again
func migrateRefresh(currpath, driver, connStr string) {
migrate("refresh", currpath, driver, connStr)
}
// migrate generates source code, build it, and invoke the binary who does the actual migration
func migrate(goal, currpath, driver, connStr string) {
dir := path.Join(currpath, "database", "migrations")
@ -153,7 +121,7 @@ func migrate(goal, currpath, driver, connStr string) {
// Connect to database
db, err := sql.Open(driver, connStr)
if err != nil {
logger.Fatalf("Could not connect to database using '%s': %s", connStr, err)
beeLogger.Log.Fatalf("Could not connect to database using '%s': %s", connStr, err)
}
defer db.Close()
@ -171,44 +139,44 @@ func migrate(goal, currpath, driver, connStr string) {
func checkForSchemaUpdateTable(db *sql.DB, driver string) {
showTableSQL := showMigrationsTableSQL(driver)
if rows, err := db.Query(showTableSQL); err != nil {
logger.Fatalf("Could not show migrations table: %s", err)
beeLogger.Log.Fatalf("Could not show migrations table: %s", err)
} else if !rows.Next() {
// No migrations table, create new ones
createTableSQL := createMigrationsTableSQL(driver)
logger.Infof("Creating 'migrations' table...")
beeLogger.Log.Infof("Creating 'migrations' table...")
if _, err := db.Query(createTableSQL); err != nil {
logger.Fatalf("Could not create migrations table: %s", err)
beeLogger.Log.Fatalf("Could not create migrations table: %s", err)
}
}
// Checking that migrations table schema are expected
selectTableSQL := selectMigrationsTableSQL(driver)
if rows, err := db.Query(selectTableSQL); err != nil {
logger.Fatalf("Could not show columns of migrations table: %s", err)
beeLogger.Log.Fatalf("Could not show columns of migrations table: %s", err)
} else {
for rows.Next() {
var fieldBytes, typeBytes, nullBytes, keyBytes, defaultBytes, extraBytes []byte
if err := rows.Scan(&fieldBytes, &typeBytes, &nullBytes, &keyBytes, &defaultBytes, &extraBytes); err != nil {
logger.Fatalf("Could not read column information: %s", err)
beeLogger.Log.Fatalf("Could not read column information: %s", err)
}
fieldStr, typeStr, nullStr, keyStr, defaultStr, extraStr :=
string(fieldBytes), string(typeBytes), string(nullBytes), string(keyBytes), string(defaultBytes), string(extraBytes)
if fieldStr == "id_migration" {
if keyStr != "PRI" || extraStr != "auto_increment" {
logger.Hint("Expecting KEY: PRI, EXTRA: auto_increment")
logger.Fatalf("Column migration.id_migration type mismatch: KEY: %s, EXTRA: %s", keyStr, extraStr)
beeLogger.Log.Hint("Expecting KEY: PRI, EXTRA: auto_increment")
beeLogger.Log.Fatalf("Column migration.id_migration type mismatch: KEY: %s, EXTRA: %s", keyStr, extraStr)
}
} else if fieldStr == "name" {
if !strings.HasPrefix(typeStr, "varchar") || nullStr != "YES" {
logger.Hint("Expecting TYPE: varchar, NULL: YES")
logger.Fatalf("Column migration.name type mismatch: TYPE: %s, NULL: %s", typeStr, nullStr)
beeLogger.Log.Hint("Expecting TYPE: varchar, NULL: YES")
beeLogger.Log.Fatalf("Column migration.name type mismatch: TYPE: %s, NULL: %s", typeStr, nullStr)
}
} else if fieldStr == "created_at" {
if typeStr != "timestamp" || defaultStr != "CURRENT_TIMESTAMP" {
logger.Hint("Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP")
logger.Fatalf("Column migration.timestamp type mismatch: TYPE: %s, DEFAULT: %s", typeStr, defaultStr)
beeLogger.Log.Hint("Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP")
beeLogger.Log.Fatalf("Column migration.timestamp type mismatch: TYPE: %s, DEFAULT: %s", typeStr, defaultStr)
}
}
}
@ -252,22 +220,22 @@ func selectMigrationsTableSQL(driver string) string {
func getLatestMigration(db *sql.DB, goal string) (file string, createdAt int64) {
sql := "SELECT name FROM migrations where status = 'update' ORDER BY id_migration DESC LIMIT 1"
if rows, err := db.Query(sql); err != nil {
logger.Fatalf("Could not retrieve migrations: %s", err)
beeLogger.Log.Fatalf("Could not retrieve migrations: %s", err)
} else {
if rows.Next() {
if err := rows.Scan(&file); err != nil {
logger.Fatalf("Could not read migrations in database: %s", err)
beeLogger.Log.Fatalf("Could not read migrations in database: %s", err)
}
createdAtStr := file[len(file)-15:]
if t, err := time.Parse("20060102_150405", createdAtStr); err != nil {
logger.Fatalf("Could not parse time: %s", err)
beeLogger.Log.Fatalf("Could not parse time: %s", err)
} else {
createdAt = t.Unix()
}
} else {
// migration table has no 'update' record, no point rolling back
if goal == "rollback" {
logger.Fatal("There is nothing to rollback")
beeLogger.Log.Fatal("There is nothing to rollback")
}
file, createdAt = "", 0
}
@ -279,7 +247,7 @@ func getLatestMigration(db *sql.DB, goal string) (file string, createdAt int64)
func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime int64, latestName string, task string) {
changeDir(dir)
if f, err := os.OpenFile(source, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err != nil {
logger.Fatalf("Could not create file: %s", err)
beeLogger.Log.Fatalf("Could not create file: %s", err)
} else {
content := strings.Replace(MigrationMainTPL, "{{DBDriver}}", driver, -1)
content = strings.Replace(content, "{{ConnStr}}", connStr, -1)
@ -287,9 +255,9 @@ func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime in
content = strings.Replace(content, "{{LatestName}}", latestName, -1)
content = strings.Replace(content, "{{Task}}", task, -1)
if _, err := f.WriteString(content); err != nil {
logger.Fatalf("Could not write to file: %s", err)
beeLogger.Log.Fatalf("Could not write to file: %s", err)
}
CloseFile(f)
utils.CloseFile(f)
}
}
@ -298,7 +266,7 @@ func buildMigrationBinary(dir, binary string) {
changeDir(dir)
cmd := exec.Command("go", "build", "-o", binary)
if out, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("Could not build migration binary: %s", err)
beeLogger.Log.Errorf("Could not build migration binary: %s", err)
formatShellErrOutput(string(out))
removeTempFile(dir, binary)
removeTempFile(dir, binary+".go")
@ -312,7 +280,7 @@ func runMigrationBinary(dir, binary string) {
cmd := exec.Command("./" + binary)
if out, err := cmd.CombinedOutput(); err != nil {
formatShellOutput(string(out))
logger.Errorf("Could not run migration binary: %s", err)
beeLogger.Log.Errorf("Could not run migration binary: %s", err)
removeTempFile(dir, binary)
removeTempFile(dir, binary+".go")
os.Exit(2)
@ -325,7 +293,7 @@ func runMigrationBinary(dir, binary string) {
// It exits the system when encouter an error
func changeDir(dir string) {
if err := os.Chdir(dir); err != nil {
logger.Fatalf("Could not find migration directory: %s", err)
beeLogger.Log.Fatalf("Could not find migration directory: %s", err)
}
}
@ -333,7 +301,7 @@ func changeDir(dir string) {
func removeTempFile(dir, file string) {
changeDir(dir)
if err := os.Remove(file); err != nil {
logger.Warnf("Could not remove temporary file: %s", err)
beeLogger.Log.Warnf("Could not remove temporary file: %s", err)
}
}
@ -341,7 +309,7 @@ func removeTempFile(dir, file string) {
func formatShellErrOutput(o string) {
for _, line := range strings.Split(o, "\n") {
if line != "" {
logger.Errorf("|> %s", line)
beeLogger.Log.Errorf("|> %s", line)
}
}
}
@ -350,7 +318,7 @@ func formatShellErrOutput(o string) {
func formatShellOutput(o string) {
for _, line := range strings.Split(o, "\n") {
if line != "" {
logger.Infof("|> %s", line)
beeLogger.Log.Infof("|> %s", line)
}
}
}
@ -421,3 +389,23 @@ CREATE TABLE migrations (
status migrations_status
)`
)
// MigrateUpdate does the schema update
func MigrateUpdate(currpath, driver, connStr string) {
migrate("upgrade", currpath, driver, connStr)
}
// MigrateRollback rolls back the latest migration
func MigrateRollback(currpath, driver, connStr string) {
migrate("rollback", currpath, driver, connStr)
}
// MigrateReset rolls back all migrations
func MigrateReset(currpath, driver, connStr string) {
migrate("reset", currpath, driver, connStr)
}
// migrationRefresh rolls back all migrations and start over again
func MigrateRefresh(currpath, driver, connStr string) {
migrate("refresh", currpath, driver, connStr)
}

View File

@ -12,16 +12,22 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package new
import (
"fmt"
"os"
path "path/filepath"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
)
var cmdNew = &Command{
var CmdNew = &commands.Command{
UsageLine: "new [appname]",
Short: "Creates a Beego application",
Long: `
@ -47,74 +53,8 @@ Creates a Beego application for the given app name in the current directory.
index.tpl
`,
PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() },
Run: createApp,
}
func createApp(cmd *Command, args []string) int {
output := cmd.Out()
if len(args) != 1 {
logger.Fatal("Argument [appname] is missing")
}
apppath, packpath, err := checkEnv(args[0])
if err != nil {
logger.Fatalf("%s", err)
}
if isExist(apppath) {
logger.Errorf(bold("Application '%s' already exists"), apppath)
logger.Warn(bold("Do you want to overwrite it? [Yes|No] "))
if !askForConfirmation() {
os.Exit(2)
}
}
logger.Info("Creating application...")
os.MkdirAll(apppath, 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "controllers"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "routers"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "tests"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static", "js"), 0755)
WriteToFile(path.Join(apppath, "static", "js", "reload.min.js"), reloadJsClient)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "js")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static", "css"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "css")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static", "img"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "img")+string(path.Separator), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "views"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m")
WriteToFile(path.Join(apppath, "conf", "app.conf"), strings.Replace(appconf, "{{.Appname}}", path.Base(args[0]), -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "default.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "controllers", "default.go"), controllers)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views", "index.tpl"), "\x1b[0m")
WriteToFile(path.Join(apppath, "views", "index.tpl"), indextpl)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers", "router.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests", "default_test.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", packpath, -1))
logger.Success("New application successfully created!")
return 0
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: CreateApp,
}
var appconf = `appname = {{.Appname}}
@ -303,3 +243,73 @@ var indextpl = `<!DOCTYPE html>
var reloadJsClient = `function b(a){var c=new WebSocket(a);c.onclose=function(){setTimeout(function(){b(a)},2E3)};c.onmessage=function(){location.reload()}}try{if(window.WebSocket)try{b("ws://localhost:12450/reload")}catch(a){console.error(a)}else console.log("Your browser does not support WebSockets.")}catch(a){console.error("Exception during connecting to Reload:",a)};
`
func init() {
commands.AvailableCommands = append(commands.AvailableCommands, CmdNew)
}
func CreateApp(cmd *commands.Command, args []string) int {
output := cmd.Out()
if len(args) != 1 {
beeLogger.Log.Fatal("Argument [appname] is missing")
}
apppath, packpath, err := utils.CheckEnv(args[0])
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
if utils.IsExist(apppath) {
beeLogger.Log.Errorf(colors.Bold("Application '%s' already exists"), apppath)
beeLogger.Log.Warn(colors.Bold("Do you want to overwrite it? [Yes|No] "))
if !utils.AskForConfirmation() {
os.Exit(2)
}
}
beeLogger.Log.Info("Creating application...")
os.MkdirAll(apppath, 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "controllers"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "routers"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "tests"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static", "js"), 0755)
utils.WriteToFile(path.Join(apppath, "static", "js", "reload.min.js"), reloadJsClient)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "js")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static", "css"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "css")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static", "img"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "img")+string(path.Separator), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "views"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "conf", "app.conf"), strings.Replace(appconf, "{{.Appname}}", path.Base(args[0]), -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "default.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "controllers", "default.go"), controllers)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views", "index.tpl"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "views", "index.tpl"), indextpl)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers", "router.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests", "default_test.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", packpath, -1))
beeLogger.Log.Success("New application successfully created!")
return 0
}

View File

@ -1,18 +1,4 @@
// 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.
package main
package pack
import (
"archive/tar"
@ -31,9 +17,14 @@ import (
"strings"
"syscall"
"time"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
)
var cmdPack = &Command{
var CmdPack = &commands.Command{
CustomFlags: true,
UsageLine: "pack",
Short: "Compresses a Beego application into a single file",
@ -43,7 +34,7 @@ var cmdPack = &Command{
{{"Example:"|bold}}
$ bee pack -v -ba="-ldflags '-s -w'"
`,
PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() },
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: packApp,
}
@ -52,27 +43,16 @@ var (
excludeP string
excludeS string
outputP string
excludeR ListOpts
excludeR utils.ListOpts
fsym bool
ssym bool
build bool
buildArgs string
buildEnvs ListOpts
buildEnvs utils.ListOpts
verbose bool
format string
)
type ListOpts []string
func (opts *ListOpts) String() string {
return fmt.Sprint(*opts)
}
func (opts *ListOpts) Set(value string) error {
*opts = append(*opts, value)
return nil
}
func init() {
fs := flag.NewFlagSet("pack", flag.ContinueOnError)
fs.StringVar(&appPath, "p", "", "Set the application path. Defaults to the current path.")
@ -87,7 +67,8 @@ func init() {
fs.BoolVar(&fsym, "fs", false, "Tell the command to follow symlinks. Defaults to false.")
fs.BoolVar(&ssym, "ss", false, "Tell the command to skip symlinks. Defaults to false.")
fs.BoolVar(&verbose, "v", false, "Be more verbose during the operation. Defaults to false.")
cmdPack.Flag = *fs
CmdPack.Flag = *fs
commands.AvailableCommands = append(commands.AvailableCommands, CmdPack)
}
type walker interface {
@ -115,10 +96,6 @@ type walkFileTree struct {
output *io.Writer
}
func (wft *walkFileTree) setPrefix(prefix string) {
wft.prefix = prefix
}
func (wft *walkFileTree) isExclude(fPath string) bool {
if fPath == "" {
return true
@ -316,12 +293,12 @@ func (wft *tarWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) {
return false, err
}
if isSym == false {
if !isSym {
fr, err := os.Open(fpath)
if err != nil {
return false, err
}
defer CloseFile(fr)
defer utils.CloseFile(fr)
_, err = io.Copy(tw, fr)
if err != nil {
return false, err
@ -352,12 +329,12 @@ func (wft *zipWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) {
return false, err
}
if isSym == false {
if !isSym {
fr, err := os.Open(fpath)
if err != nil {
return false, err
}
defer CloseFile(fr)
defer utils.CloseFile(fr)
_, err = io.Copy(w, fr)
if err != nil {
return false, err
@ -379,10 +356,10 @@ func (wft *zipWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) {
func packDirectory(output io.Writer, excludePrefix []string, excludeSuffix []string,
excludeRegexp []*regexp.Regexp, includePath ...string) (err error) {
logger.Infof("Excluding relpath prefix: %s", strings.Join(excludePrefix, ":"))
logger.Infof("Excluding relpath suffix: %s", strings.Join(excludeSuffix, ":"))
beeLogger.Log.Infof("Excluding relpath prefix: %s", strings.Join(excludePrefix, ":"))
beeLogger.Log.Infof("Excluding relpath suffix: %s", strings.Join(excludeSuffix, ":"))
if len(excludeRegexp) > 0 {
logger.Infof("Excluding filename regex: `%s`", strings.Join(excludeR, "`, `"))
beeLogger.Log.Infof("Excluding filename regex: `%s`", strings.Join(excludeR, "`, `"))
}
w, err := os.OpenFile(outputP, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
@ -437,7 +414,7 @@ func packDirectory(output io.Writer, excludePrefix []string, excludeSuffix []str
return
}
func packApp(cmd *Command, args []string) int {
func packApp(cmd *commands.Command, args []string) int {
output := cmd.Out()
curPath, _ := os.Getwd()
thePath := ""
@ -454,19 +431,19 @@ func packApp(cmd *Command, args []string) int {
}
cmd.Flag.Parse(nArgs)
if path.IsAbs(appPath) == false {
if !path.IsAbs(appPath) {
appPath = path.Join(curPath, appPath)
}
thePath, err := path.Abs(appPath)
if err != nil {
logger.Fatalf("Wrong application path: %s", thePath)
beeLogger.Log.Fatalf("Wrong application path: %s", thePath)
}
if stat, err := os.Stat(thePath); os.IsNotExist(err) || stat.IsDir() == false {
logger.Fatalf("Application path does not exist: %s", thePath)
if stat, err := os.Stat(thePath); os.IsNotExist(err) || !stat.IsDir() {
beeLogger.Log.Fatalf("Application path does not exist: %s", thePath)
}
logger.Infof("Packaging application on '%s'...", thePath)
beeLogger.Log.Infof("Packaging application on '%s'...", thePath)
appName := path.Base(thePath)
@ -488,12 +465,12 @@ func packApp(cmd *Command, args []string) int {
// Remove the tmpdir once bee pack is done
err := os.RemoveAll(tmpdir)
if err != nil {
logger.Error("Failed to remove the generated temp dir")
beeLogger.Log.Error("Failed to remove the generated temp dir")
}
}()
if build {
logger.Info("Building application...")
beeLogger.Log.Info("Building application...")
var envs []string
for _, env := range buildEnvs {
parts := strings.SplitN(env, "=", 2)
@ -515,7 +492,7 @@ func packApp(cmd *Command, args []string) int {
os.Setenv("GOOS", goos)
os.Setenv("GOARCH", goarch)
logger.Infof("Using: GOOS=%s GOARCH=%s", goos, goarch)
beeLogger.Log.Infof("Using: GOOS=%s GOARCH=%s", goos, goarch)
binPath := path.Join(tmpdir, appName)
if goos == "windows" {
@ -538,10 +515,10 @@ func packApp(cmd *Command, args []string) int {
execmd.Dir = thePath
err = execmd.Run()
if err != nil {
logger.Fatal(err.Error())
beeLogger.Log.Fatal(err.Error())
}
logger.Success("Build Successful!")
beeLogger.Log.Success("Build Successful!")
}
switch format {
@ -552,14 +529,14 @@ func packApp(cmd *Command, args []string) int {
outputN := appName + "." + format
if outputP == "" || path.IsAbs(outputP) == false {
if outputP == "" || !path.IsAbs(outputP) {
outputP = path.Join(curPath, outputP)
}
if _, err := os.Stat(outputP); err != nil {
err = os.MkdirAll(outputP, 0755)
if err != nil {
logger.Fatal(err.Error())
beeLogger.Log.Fatal(err.Error())
}
}
@ -581,20 +558,20 @@ func packApp(cmd *Command, args []string) int {
for _, r := range excludeR {
if len(r) > 0 {
if re, err := regexp.Compile(r); err != nil {
logger.Fatal(err.Error())
beeLogger.Log.Fatal(err.Error())
} else {
exr = append(exr, re)
}
}
}
logger.Infof("Writing to output: %s", outputP)
beeLogger.Log.Infof("Writing to output: %s", outputP)
err = packDirectory(output, exp, exs, exr, tmpdir, thePath)
if err != nil {
logger.Fatal(err.Error())
beeLogger.Log.Fatal(err.Error())
}
logger.Success("Application packed!")
beeLogger.Log.Success("Application packed!")
return 0
}

88
cmd/commands/run/docs.go Normal file
View File

@ -0,0 +1,88 @@
package run
import (
"archive/zip"
"io"
"net/http"
"os"
"strings"
beeLogger "github.com/beego/bee/logger"
)
var (
swaggerVersion = "2"
swaggerlink = "https://github.com/beego/swagger/archive/v" + swaggerVersion + ".zip"
)
func downloadFromURL(url, fileName string) {
var down bool
if fd, err := os.Stat(fileName); err != nil && os.IsNotExist(err) {
down = true
} else if fd.Size() == int64(0) {
down = true
} else {
beeLogger.Log.Infof("'%s' already exists", fileName)
return
}
if down {
beeLogger.Log.Infof("Downloading '%s' to '%s'...", url, fileName)
output, err := os.Create(fileName)
if err != nil {
beeLogger.Log.Errorf("Error while creating '%s': %s", fileName, err)
return
}
defer output.Close()
response, err := http.Get(url)
if err != nil {
beeLogger.Log.Errorf("Error while downloading '%s': %s", url, err)
return
}
defer response.Body.Close()
n, err := io.Copy(output, response.Body)
if err != nil {
beeLogger.Log.Errorf("Error while downloading '%s': %s", url, err)
return
}
beeLogger.Log.Successf("%d bytes downloaded!", n)
}
}
func unzipAndDelete(src string) error {
beeLogger.Log.Infof("Unzipping '%s'...", src)
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer r.Close()
rp := strings.NewReplacer("swagger-"+swaggerVersion, "swagger")
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
return err
}
defer rc.Close()
fname := rp.Replace(f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(fname, f.Mode())
} else {
f, err := os.OpenFile(
fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, rc)
if err != nil {
return err
}
}
}
beeLogger.Log.Successf("Done! Deleting '%s'...", src)
return os.RemoveAll(src)
}

View File

@ -11,13 +11,14 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package main
package run
import (
"bytes"
"net/http"
"time"
beeLogger "github.com/beego/bee/logger"
"github.com/gorilla/websocket"
)
@ -70,7 +71,7 @@ func (c *wsClient) readPump() {
_, _, err := c.conn.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
logger.Errorf("An error happened when reading from the Websocket client: %v", err)
beeLogger.Log.Errorf("An error happened when reading from the Websocket client: %v", err)
}
break
}
@ -109,7 +110,7 @@ func (c *wsClient) writePump() {
n := len(c.send)
for i := 0; i < n; i++ {
w.Write(newline)
w.Write([]byte("/n"))
w.Write(<-c.send)
}
@ -155,13 +156,13 @@ func startReloadServer() {
})
go startServer()
logger.Infof("Reload server listening at %s", reloadAddress)
beeLogger.Log.Infof("Reload server listening at %s", reloadAddress)
}
func startServer() {
err := http.ListenAndServe(reloadAddress, nil)
if err != nil {
logger.Errorf("Failed to start up the Reload server: %v", err)
beeLogger.Log.Errorf("Failed to start up the Reload server: %v", err)
return
}
}
@ -175,7 +176,7 @@ func sendReload(payload string) {
func handleWsRequest(broker *wsBroker, w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
logger.Errorf("error while upgrading server connection: %v", err)
beeLogger.Log.Errorf("error while upgrading server connection: %v", err)
return
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package run
import (
"io/ioutil"
@ -20,25 +20,31 @@ import (
path "path/filepath"
"runtime"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/config"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
)
var cmdRun = &Command{
var CmdRun = &commands.Command{
UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-vendor=true] [-e=folderToExclude] [-ex=extraPackageToWatch] [-tags=goBuildTags] [-runmode=BEEGO_RUNMODE]",
Short: "Run the application by starting a local development server",
Long: `
Run command will supervise the filesystem of the application for any changes, and recompile/restart it.
`,
PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() },
Run: runApp,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: RunApp,
}
var (
mainFiles ListOpts
downdoc docValue
gendoc docValue
mainFiles utils.ListOpts
downdoc utils.DocValue
gendoc utils.DocValue
// The flags list of the paths excluded from watching
excludedPaths strFlags
excludedPaths utils.StrFlags
// Pass through to -tags arg of "go build"
buildTags string
// Application path
@ -54,66 +60,63 @@ var (
// Current runmode
runmode string
// Extra directories
extraPackages strFlags
extraPackages utils.StrFlags
)
var started = make(chan bool)
func init() {
cmdRun.Flag.Var(&mainFiles, "main", "Specify main go files.")
cmdRun.Flag.Var(&gendoc, "gendoc", "Enable auto-generate the docs.")
cmdRun.Flag.Var(&downdoc, "downdoc", "Enable auto-download of the swagger file if it does not exist.")
cmdRun.Flag.Var(&excludedPaths, "e", "List of paths to exclude.")
cmdRun.Flag.BoolVar(&vendorWatch, "vendor", false, "Enable watch vendor folder.")
cmdRun.Flag.StringVar(&buildTags, "tags", "", "Set the build tags. See: https://golang.org/pkg/go/build/")
cmdRun.Flag.StringVar(&runmode, "runmode", "", "Set the Beego run mode.")
cmdRun.Flag.Var(&extraPackages, "ex", "List of extra package to watch.")
CmdRun.Flag.Var(&mainFiles, "main", "Specify main go files.")
CmdRun.Flag.Var(&gendoc, "gendoc", "Enable auto-generate the docs.")
CmdRun.Flag.Var(&downdoc, "downdoc", "Enable auto-download of the swagger file if it does not exist.")
CmdRun.Flag.Var(&excludedPaths, "e", "List of paths to exclude.")
CmdRun.Flag.BoolVar(&vendorWatch, "vendor", false, "Enable watch vendor folder.")
CmdRun.Flag.StringVar(&buildTags, "tags", "", "Set the build tags. See: https://golang.org/pkg/go/build/")
CmdRun.Flag.StringVar(&runmode, "runmode", "", "Set the Beego run mode.")
CmdRun.Flag.Var(&extraPackages, "ex", "List of extra package to watch.")
exit = make(chan bool)
commands.AvailableCommands = append(commands.AvailableCommands, CmdRun)
}
func runApp(cmd *Command, args []string) int {
func RunApp(cmd *commands.Command, args []string) int {
if len(args) == 0 || args[0] == "watchall" {
currpath, _ = os.Getwd()
if found, _gopath, _ := SearchGOPATHs(currpath); found {
if found, _gopath, _ := utils.SearchGOPATHs(currpath); found {
appname = path.Base(currpath)
currentGoPath = _gopath
} else {
logger.Fatalf("No application '%s' found in your GOPATH", currpath)
beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", currpath)
}
} else {
// Check if passed Bee application path/name exists in the GOPATH(s)
if found, _gopath, _path := SearchGOPATHs(args[0]); found {
if found, _gopath, _path := utils.SearchGOPATHs(args[0]); found {
currpath = _path
currentGoPath = _gopath
appname = path.Base(currpath)
} else {
logger.Fatalf("No application '%s' found in your GOPATH", args[0])
beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", args[0])
}
if strings.HasSuffix(appname, ".go") && isExist(currpath) {
logger.Warnf("The appname is in conflict with file's current path. Do you want to build appname as '%s'", appname)
logger.Info("Do you want to overwrite it? [yes|no] ")
if !askForConfirmation() {
if strings.HasSuffix(appname, ".go") && utils.IsExist(currpath) {
beeLogger.Log.Warnf("The appname is in conflict with file's current path. Do you want to build appname as '%s'", appname)
beeLogger.Log.Info("Do you want to overwrite it? [yes|no] ")
if !utils.AskForConfirmation() {
return 0
}
}
}
logger.Infof("Using '%s' as 'appname'", appname)
beeLogger.Log.Infof("Using '%s' as 'appname'", appname)
logger.Debugf("Current path: %s", __FILE__(), __LINE__(), currpath)
beeLogger.Log.Debugf("Current path: %s", utils.FILE(), utils.LINE(), currpath)
if runmode == "prod" || runmode == "dev" {
os.Setenv("BEEGO_RUNMODE", runmode)
logger.Infof("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE"))
beeLogger.Log.Infof("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE"))
} else if runmode != "" {
os.Setenv("BEEGO_RUNMODE", runmode)
logger.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE"))
beeLogger.Log.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE"))
} else if os.Getenv("BEEGO_RUNMODE") != "" {
logger.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE"))
}
err := loadConfig()
if err != nil {
logger.Fatalf("Failed to load configuration: %s", err)
beeLogger.Log.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE"))
}
var paths []string
@ -121,17 +124,17 @@ func runApp(cmd *Command, args []string) int {
// Because monitor files has some issues, we watch current directory
// and ignore non-go files.
for _, p := range conf.DirStruct.Others {
for _, p := range config.Conf.DirStruct.Others {
paths = append(paths, strings.Replace(p, "$GOPATH", currentGoPath, -1))
}
if len(extraPackages) > 0 {
// get the full path
for _, packagePath := range extraPackages {
if found, _, _fullPath := SearchGOPATHs(packagePath); found {
if found, _, _fullPath := utils.SearchGOPATHs(packagePath); found {
readAppDirectories(_fullPath, &paths)
} else {
logger.Warnf("No extra package '%s' found in your GOPATH", packagePath)
beeLogger.Log.Warnf("No extra package '%s' found in your GOPATH", packagePath)
}
}
// let paths unique
@ -163,7 +166,7 @@ func runApp(cmd *Command, args []string) int {
}
// Start the Reload server (if enabled)
if conf.EnableReload {
if config.Conf.EnableReload {
startReloadServer()
}
if gendoc == "true" {
@ -205,16 +208,16 @@ func readAppDirectories(directory string, paths *[]string) {
continue
}
if fileInfo.IsDir() == true && fileInfo.Name()[0] != '.' {
if fileInfo.IsDir() && fileInfo.Name()[0] != '.' {
readAppDirectories(directory+"/"+fileInfo.Name(), paths)
continue
}
if useDirectory == true {
if useDirectory {
continue
}
if path.Ext(fileInfo.Name()) == ".go" || (ifStaticFile(fileInfo.Name()) && conf.EnableReload) {
if path.Ext(fileInfo.Name()) == ".go" || (ifStaticFile(fileInfo.Name()) && config.Conf.EnableReload) {
*paths = append(*paths, directory)
useDirectory = true
}
@ -227,16 +230,16 @@ func isExcluded(filePath string) bool {
for _, p := range excludedPaths {
absP, err := path.Abs(p)
if err != nil {
logger.Errorf("Cannot get absolute path of '%s'", p)
beeLogger.Log.Errorf("Cannot get absolute path of '%s'", p)
continue
}
absFilePath, err := path.Abs(filePath)
if err != nil {
logger.Errorf("Cannot get absolute path of '%s'", filePath)
beeLogger.Log.Errorf("Cannot get absolute path of '%s'", filePath)
break
}
if strings.HasPrefix(absFilePath, absP) {
logger.Infof("'%s' is not being watched", filePath)
beeLogger.Log.Infof("'%s' is not being watched", filePath)
return true
}
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package run
import (
"bytes"
@ -24,6 +24,10 @@ import (
"sync"
"time"
"github.com/beego/bee/config"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
"github.com/fsnotify/fsnotify"
)
@ -46,7 +50,7 @@ var (
func NewWatcher(paths []string, files []string, isgenerate bool) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
logger.Fatalf("Failed to create watcher: %s", err)
beeLogger.Log.Fatalf("Failed to create watcher: %s", err)
}
go func() {
@ -55,7 +59,7 @@ func NewWatcher(paths []string, files []string, isgenerate bool) {
case e := <-watcher.Events:
isBuild := true
if ifStaticFile(e.Name) && conf.EnableReload {
if ifStaticFile(e.Name) && config.Conf.EnableReload {
sendReload(e.String())
continue
}
@ -69,14 +73,14 @@ func NewWatcher(paths []string, files []string, isgenerate bool) {
mt := getFileModTime(e.Name)
if t := eventTime[e.Name]; mt == t {
logger.Infof(bold("Skipping: ")+"%s", e.String())
beeLogger.Log.Infof(colors.Bold("Skipping: ")+"%s", e.String())
isBuild = false
}
eventTime[e.Name] = mt
if isBuild {
logger.Infof("Event fired: %s", e)
beeLogger.Log.Infof("Event fired: %s", e)
go func() {
// Wait 1s before autobuild until there is no file change.
scheduleTime = time.Now().Add(1 * time.Second)
@ -85,17 +89,17 @@ func NewWatcher(paths []string, files []string, isgenerate bool) {
}()
}
case err := <-watcher.Errors:
logger.Warnf("Watcher error: %s", err.Error()) // No need to exit here
beeLogger.Log.Warnf("Watcher error: %s", err.Error()) // No need to exit here
}
}
}()
logger.Info("Initializing watcher...")
beeLogger.Log.Info("Initializing watcher...")
for _, path := range paths {
logger.Infof(bold("Watching: ")+"%s", path)
beeLogger.Log.Infof(colors.Bold("Watching: ")+"%s", path)
err = watcher.Add(path)
if err != nil {
logger.Fatalf("Failed to watch directory: %s", err)
beeLogger.Log.Fatalf("Failed to watch directory: %s", err)
}
}
}
@ -105,14 +109,14 @@ func getFileModTime(path string) int64 {
path = strings.Replace(path, "\\", "/", -1)
f, err := os.Open(path)
if err != nil {
logger.Errorf("Failed to open file on '%s': %s", path, err)
beeLogger.Log.Errorf("Failed to open file on '%s': %s", path, err)
return time.Now().Unix()
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
logger.Errorf("Failed to get file stats: %s", err)
beeLogger.Log.Errorf("Failed to get file stats: %s", err)
return time.Now().Unix()
}
@ -127,7 +131,7 @@ func AutoBuild(files []string, isgenerate bool) {
os.Chdir(currpath)
cmdName := "go"
if conf.Gopm.Enable {
if config.Conf.Gopm.Enable {
cmdName = "gopm"
}
@ -138,14 +142,14 @@ func AutoBuild(files []string, isgenerate bool) {
)
// For applications use full import path like "github.com/.../.."
// are able to use "go install" to reduce build time.
if conf.GoInstall {
if config.Conf.GoInstall {
icmd := exec.Command(cmdName, "install", "-v")
icmd.Stdout = os.Stdout
icmd.Stderr = os.Stderr
icmd.Env = append(os.Environ(), "GOGC=off")
icmd.Run()
}
if conf.Gopm.Install {
if config.Conf.Gopm.Install {
icmd := exec.Command("go", "list", "./...")
icmd.Stdout = &stdout
icmd.Env = append(os.Environ(), "GOGC=off")
@ -169,15 +173,15 @@ func AutoBuild(files []string, isgenerate bool) {
}
if isgenerate {
logger.Info("Generating the docs...")
beeLogger.Log.Info("Generating the docs...")
icmd := exec.Command("bee", "generate", "docs")
icmd.Env = append(os.Environ(), "GOGC=off")
err = icmd.Run()
if err != nil {
logger.Errorf("Failed to generate the docs.")
beeLogger.Log.Errorf("Failed to generate the docs.")
return
}
logger.Success("Docs generated!")
beeLogger.Log.Success("Docs generated!")
}
if err == nil {
@ -198,12 +202,12 @@ func AutoBuild(files []string, isgenerate bool) {
bcmd.Stderr = &stderr
err = bcmd.Run()
if err != nil {
logger.Errorf("Failed to build the application: %s", stderr.String())
beeLogger.Log.Errorf("Failed to build the application: %s", stderr.String())
return
}
}
logger.Success("Built Successfully!")
beeLogger.Log.Success("Built Successfully!")
Restart(appname)
}
@ -211,39 +215,39 @@ func AutoBuild(files []string, isgenerate bool) {
func Kill() {
defer func() {
if e := recover(); e != nil {
logger.Infof("Kill recover: %s", e)
beeLogger.Log.Infof("Kill recover: %s", e)
}
}()
if cmd != nil && cmd.Process != nil {
err := cmd.Process.Kill()
if err != nil {
logger.Errorf("Error while killing cmd process: %s", err)
beeLogger.Log.Errorf("Error while killing cmd process: %s", err)
}
}
}
// Restart kills the running command process and starts it again
func Restart(appname string) {
logger.Debugf("Kill running process", __FILE__(), __LINE__())
beeLogger.Log.Debugf("Kill running process", utils.FILE(), utils.LINE())
Kill()
go Start(appname)
}
// Start starts the command process
func Start(appname string) {
logger.Infof("Restarting '%s'...", appname)
if strings.Index(appname, "./") == -1 {
beeLogger.Log.Infof("Restarting '%s'...", appname)
if !strings.Contains(appname, "./") {
appname = "./" + appname
}
cmd = exec.Command(appname)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Args = append([]string{appname}, conf.CmdArgs...)
cmd.Env = append(os.Environ(), conf.Envs...)
cmd.Args = append([]string{appname}, config.Conf.CmdArgs...)
cmd.Env = append(os.Environ(), config.Conf.Envs...)
go cmd.Run()
logger.Successf("'%s' is running...", appname)
beeLogger.Log.Successf("'%s' is running...", appname)
started <- true
}
@ -262,7 +266,7 @@ func shouldIgnoreFile(filename string) bool {
for _, regex := range ignoredFilesRegExps {
r, err := regexp.Compile(regex)
if err != nil {
logger.Fatalf("Could not compile regular expression: %s", err)
beeLogger.Log.Fatalf("Could not compile regular expression: %s", err)
}
if r.MatchString(filename) {
return true

View File

@ -1,4 +1,4 @@
package main
package version
import (
"io"
@ -6,6 +6,10 @@ import (
"os"
"runtime"
"text/template"
"time"
beeLogger "github.com/beego/bee/logger"
)
// RuntimeInfo holds information about the current runtime.
@ -26,12 +30,12 @@ type RuntimeInfo struct {
// print the banner in case of error.
func InitBanner(out io.Writer, in io.Reader) {
if in == nil {
logger.Fatal("The input is nil")
beeLogger.Log.Fatal("The input is nil")
}
banner, err := ioutil.ReadAll(in)
if err != nil {
logger.Fatalf("Error while trying to read the banner: %s", err)
beeLogger.Log.Fatalf("Error while trying to read the banner: %s", err)
}
show(out, string(banner))
@ -43,11 +47,11 @@ func show(out io.Writer, content string) {
Parse(content)
if err != nil {
logger.Fatalf("Cannot parse the banner template: %s", err)
beeLogger.Log.Fatalf("Cannot parse the banner template: %s", err)
}
err = t.Execute(out, RuntimeInfo{
getGoVersion(),
GetGoVersion(),
runtime.GOOS,
runtime.GOARCH,
runtime.NumCPU(),
@ -55,7 +59,14 @@ func show(out io.Writer, content string) {
runtime.GOROOT(),
runtime.Compiler,
version,
getBeegoVersion(),
GetBeegoVersion(),
})
MustCheck(err)
if err != nil {
beeLogger.Log.Error(err.Error())
}
}
// Now returns the current local time in the specified layout
func Now(layout string) string {
return time.Now().Format(layout)
}

View File

@ -1,4 +1,4 @@
package main
package version
import (
"bufio"
@ -14,18 +14,12 @@ import (
"runtime"
"strings"
"github.com/beego/bee/cmd/commands"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"gopkg.in/yaml.v2"
)
var cmdVersion = &Command{
UsageLine: "version",
Short: "Prints the current Bee version",
Long: `
Prints the current Bee, Beego and Go version alongside the platform information.
`,
Run: versionCmd,
}
const verboseVersionBanner string = `%s%s______
| ___ \
| |_/ / ___ ___
@ -52,21 +46,33 @@ const shortVersionBanner = `______
\____/ \___| \___| v{{ .BeeVersion }}
`
var CmdVersion = &commands.Command{
UsageLine: "version",
Short: "Prints the current Bee version",
Long: `
Prints the current Bee, Beego and Go version alongside the platform information.
`,
Run: versionCmd,
}
var outputFormat string
const version = "1.8.0"
func init() {
fs := flag.NewFlagSet("version", flag.ContinueOnError)
fs.StringVar(&outputFormat, "o", "", "Set the output format. Either json or yaml.")
cmdVersion.Flag = *fs
CmdVersion.Flag = *fs
commands.AvailableCommands = append(commands.AvailableCommands, CmdVersion)
}
func versionCmd(cmd *Command, args []string) int {
func versionCmd(cmd *commands.Command, args []string) int {
cmd.Flag.Parse(args)
stdout := cmd.Out()
if outputFormat != "" {
runtimeInfo := RuntimeInfo{
getGoVersion(),
GetGoVersion(),
runtime.GOOS,
runtime.GOARCH,
runtime.NumCPU(),
@ -74,20 +80,24 @@ func versionCmd(cmd *Command, args []string) int {
runtime.GOROOT(),
runtime.Compiler,
version,
getBeegoVersion(),
GetBeegoVersion(),
}
switch outputFormat {
case "json":
{
b, err := json.MarshalIndent(runtimeInfo, "", " ")
MustCheck(err)
if err != nil {
beeLogger.Log.Error(err.Error())
}
fmt.Println(string(b))
return 0
}
case "yaml":
{
b, err := yaml.Marshal(&runtimeInfo)
MustCheck(err)
if err != nil {
beeLogger.Log.Error(err.Error())
}
fmt.Println(string(b))
return 0
}
@ -102,11 +112,11 @@ func versionCmd(cmd *Command, args []string) int {
// ShowShortVersionBanner prints the short version banner.
func ShowShortVersionBanner() {
output := NewColorWriter(os.Stdout)
InitBanner(output, bytes.NewBufferString(MagentaBold(shortVersionBanner)))
output := colors.NewColorWriter(os.Stdout)
InitBanner(output, bytes.NewBufferString(colors.MagentaBold(shortVersionBanner)))
}
func getBeegoVersion() string {
func GetBeegoVersion() string {
gopath := os.Getenv("GOPATH")
re, err := regexp.Compile(`VERSION = "([0-9.]+)"`)
if err != nil {
@ -125,11 +135,11 @@ func getBeegoVersion() string {
if os.IsNotExist(err) {
continue
}
logger.Error("Error while getting stats of 'beego.go'")
beeLogger.Log.Error("Error while getting stats of 'beego.go'")
}
fd, err := os.Open(filename)
if err != nil {
logger.Error("Error while reading 'beego.go'")
beeLogger.Log.Error("Error while reading 'beego.go'")
continue
}
reader := bufio.NewReader(fd)
@ -152,14 +162,14 @@ func getBeegoVersion() string {
return "Beego is not installed. Please do consider installing it first: https://github.com/astaxie/beego"
}
func getGoVersion() string {
func GetGoVersion() string {
var (
cmdOut []byte
err error
)
if cmdOut, err = exec.Command("go", "version").Output(); err != nil {
logger.Fatalf("There was an error running 'go version' command: %s", err)
beeLogger.Log.Fatalf("There was an error running 'go version' command: %s", err)
}
return strings.Split(string(cmdOut), " ")[2]
}

261
code.go
View File

@ -1,261 +0,0 @@
// Copyright 2011 Gary Burd
// Copyright 2013 Unknown
//
// 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.
package main
import (
"go/ast"
"go/printer"
"go/scanner"
"go/token"
"math"
"strconv"
)
const (
notPredeclared = iota
predeclaredType
predeclaredConstant
predeclaredFunction
)
// predeclared represents the set of all predeclared identifiers.
var predeclared = map[string]int{
"bool": predeclaredType,
"byte": predeclaredType,
"complex128": predeclaredType,
"complex64": predeclaredType,
"error": predeclaredType,
"float32": predeclaredType,
"float64": predeclaredType,
"int16": predeclaredType,
"int32": predeclaredType,
"int64": predeclaredType,
"int8": predeclaredType,
"int": predeclaredType,
"rune": predeclaredType,
"string": predeclaredType,
"uint16": predeclaredType,
"uint32": predeclaredType,
"uint64": predeclaredType,
"uint8": predeclaredType,
"uint": predeclaredType,
"uintptr": predeclaredType,
"true": predeclaredConstant,
"false": predeclaredConstant,
"iota": predeclaredConstant,
"nil": predeclaredConstant,
"append": predeclaredFunction,
"cap": predeclaredFunction,
"close": predeclaredFunction,
"complex": predeclaredFunction,
"copy": predeclaredFunction,
"delete": predeclaredFunction,
"imag": predeclaredFunction,
"len": predeclaredFunction,
"make": predeclaredFunction,
"new": predeclaredFunction,
"panic": predeclaredFunction,
"print": predeclaredFunction,
"println": predeclaredFunction,
"real": predeclaredFunction,
"recover": predeclaredFunction,
}
const (
ExportLinkAnnotation AnnotationKind = iota
AnchorAnnotation
CommentAnnotation
PackageLinkAnnotation
BuiltinAnnotation
)
// annotationVisitor collects annotations.
type annotationVisitor struct {
annotations []Annotation
}
func (v *annotationVisitor) add(kind AnnotationKind, importPath string) {
v.annotations = append(v.annotations, Annotation{Kind: kind, ImportPath: importPath})
}
func (v *annotationVisitor) ignoreName() {
v.add(-1, "")
}
func (v *annotationVisitor) Visit(n ast.Node) ast.Visitor {
switch n := n.(type) {
case *ast.TypeSpec:
v.ignoreName()
ast.Walk(v, n.Type)
case *ast.FuncDecl:
if n.Recv != nil {
ast.Walk(v, n.Recv)
}
v.ignoreName()
ast.Walk(v, n.Type)
case *ast.Field:
for range n.Names {
v.ignoreName()
}
ast.Walk(v, n.Type)
case *ast.ValueSpec:
for range n.Names {
v.add(AnchorAnnotation, "")
}
if n.Type != nil {
ast.Walk(v, n.Type)
}
for _, x := range n.Values {
ast.Walk(v, x)
}
case *ast.Ident:
switch {
case n.Obj == nil && predeclared[n.Name] != notPredeclared:
v.add(BuiltinAnnotation, "")
case n.Obj != nil && ast.IsExported(n.Name):
v.add(ExportLinkAnnotation, "")
default:
v.ignoreName()
}
case *ast.SelectorExpr:
if x, _ := n.X.(*ast.Ident); x != nil {
if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg {
if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil {
if path, err := strconv.Unquote(spec.Path.Value); err == nil {
v.add(PackageLinkAnnotation, path)
if path == "C" {
v.ignoreName()
} else {
v.add(ExportLinkAnnotation, path)
}
return nil
}
}
}
}
ast.Walk(v, n.X)
v.ignoreName()
default:
return v
}
return nil
}
func printDecl(decl ast.Node, fset *token.FileSet, buf []byte) (Code, []byte) {
v := &annotationVisitor{}
ast.Walk(v, decl)
buf = buf[:0]
err := (&printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}).Fprint(sliceWriter{&buf}, fset, decl)
if err != nil {
return Code{Text: err.Error()}, buf
}
var annotations []Annotation
var s scanner.Scanner
fset = token.NewFileSet()
file := fset.AddFile("", fset.Base(), len(buf))
s.Init(file, buf, nil, scanner.ScanComments)
loop:
for {
pos, tok, lit := s.Scan()
switch tok {
case token.EOF:
break loop
case token.COMMENT:
p := file.Offset(pos)
e := p + len(lit)
if p > math.MaxInt16 || e > math.MaxInt16 {
break loop
}
annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)})
case token.IDENT:
if len(v.annotations) == 0 {
// Oops!
break loop
}
annotation := v.annotations[0]
v.annotations = v.annotations[1:]
if annotation.Kind == -1 {
continue
}
p := file.Offset(pos)
e := p + len(lit)
if p > math.MaxInt16 || e > math.MaxInt16 {
break loop
}
annotation.Pos = int16(p)
annotation.End = int16(e)
if len(annotations) > 0 && annotation.Kind == ExportLinkAnnotation {
prev := annotations[len(annotations)-1]
if prev.Kind == PackageLinkAnnotation &&
prev.ImportPath == annotation.ImportPath &&
prev.End+1 == annotation.Pos {
// merge with previous
annotation.Pos = prev.Pos
annotations[len(annotations)-1] = annotation
continue loop
}
}
annotations = append(annotations, annotation)
}
}
return Code{Text: string(buf), Annotations: annotations}, buf
}
type AnnotationKind int16
type Annotation struct {
Pos, End int16
Kind AnnotationKind
ImportPath string
}
type Code struct {
Text string
Annotations []Annotation
}
func commentAnnotations(src string) []Annotation {
var annotations []Annotation
var s scanner.Scanner
fset := token.NewFileSet()
file := fset.AddFile("", fset.Base(), len(src))
s.Init(file, []byte(src), nil, scanner.ScanComments)
for {
pos, tok, lit := s.Scan()
switch tok {
case token.EOF:
return annotations
case token.COMMENT:
p := file.Offset(pos)
e := p + len(lit)
if p > math.MaxInt16 || e > math.MaxInt16 {
return annotations
}
annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)})
}
}
}
type sliceWriter struct{ p *[]byte }
func (w sliceWriter) Write(p []byte) (int, error) {
*w.p = append(*w.p, p...)
return len(p), nil
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package config
import (
"encoding/json"
@ -22,6 +22,7 @@ import (
"io"
"path/filepath"
beeLogger "github.com/beego/bee/logger"
"gopkg.in/yaml.v2"
)
@ -49,7 +50,7 @@ var defaultConf = `{
"enable_reload": false
}
`
var conf struct {
var Conf struct {
Version int
// gopm support
Gopm struct {
@ -79,6 +80,10 @@ var conf struct {
EnableReload bool `json:"enable_reload" yaml:"enable_reload"`
}
func init() {
loadConfig()
}
// loadConfig loads customized configuration.
func loadConfig() (err error) {
err = filepath.Walk(".", func(path string, fileInfo os.FileInfo, err error) error {
@ -91,20 +96,20 @@ func loadConfig() (err error) {
}
if fileInfo.Name() == "bee.json" {
logger.Info("Loading configuration from 'bee.json'...")
err = parseJSON(path, &conf)
beeLogger.Log.Info("Loading configuration from 'bee.json'...")
err = parseJSON(path, &Conf)
if err != nil {
logger.Errorf("Failed to parse JSON file: %s", err)
beeLogger.Log.Errorf("Failed to parse JSON file: %s", err)
return err
}
return io.EOF
}
if fileInfo.Name() == "Beefile" {
logger.Info("Loading configuration from 'Beefile'...")
err = parseYAML(path, &conf)
beeLogger.Log.Info("Loading configuration from 'Beefile'...")
err = parseYAML(path, &Conf)
if err != nil {
logger.Errorf("Failed to parse YAML file: %s", err)
beeLogger.Log.Errorf("Failed to parse YAML file: %s", err)
return err
}
return io.EOF
@ -115,8 +120,8 @@ func loadConfig() (err error) {
// In case no configuration file found or an error different than io.EOF,
// fallback to default configuration
if err != io.EOF {
logger.Info("Loading default configuration...")
err = json.Unmarshal([]byte(defaultConf), &conf)
beeLogger.Log.Info("Loading default configuration...")
err = json.Unmarshal([]byte(defaultConf), &Conf)
if err != nil {
return
}
@ -126,21 +131,21 @@ func loadConfig() (err error) {
err = nil
// Check format version
if conf.Version != confVer {
logger.Warn("Your configuration file is outdated. Please do consider updating it.")
logger.Hint("Check the latest version of bee's configuration file.")
if Conf.Version != confVer {
beeLogger.Log.Warn("Your configuration file is outdated. Please do consider updating it.")
beeLogger.Log.Hint("Check the latest version of bee's configuration file.")
}
// Set variables
if len(conf.DirStruct.Controllers) == 0 {
conf.DirStruct.Controllers = "controllers"
if len(Conf.DirStruct.Controllers) == 0 {
Conf.DirStruct.Controllers = "controllers"
}
if len(conf.DirStruct.Models) == 0 {
conf.DirStruct.Models = "models"
if len(Conf.DirStruct.Models) == 0 {
Conf.DirStruct.Models = "models"
}
// Append watch exts
watchExts = append(watchExts, conf.WatchExt...)
//watchExts = append(watchExts, Conf.WatchExt...)
return
}
@ -154,10 +159,7 @@ func parseJSON(path string, v interface{}) error {
return err
}
err = json.Unmarshal(data, v)
if err != nil {
return err
}
return nil
}
func parseYAML(path string, v interface{}) error {
@ -170,8 +172,5 @@ func parseYAML(path string, v interface{}) error {
return err
}
err = yaml.Unmarshal(data, v)
if err != nil {
return err
}
return nil
}

200
g.go
View File

@ -1,200 +0,0 @@
// 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.
package main
import (
"os"
"strings"
)
var cmdGenerate = &Command{
UsageLine: "generate [command]",
Short: "Source code generator",
Long: ` {{"To scaffold out your entire application:"|bold}}
$ bee generate scaffold [scaffoldname] [-fields="title:string,body:text"] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]
{{"To generate a Model based on fields:"|bold}}
$ bee generate model [modelname] [-fields="name:type"]
{{"To generate a controller:"|bold}}
$ bee generate controller [controllerfile]
{{"To generate a CRUD view:"|bold}}
$ bee generate view [viewpath]
{{"To generate a migration file for making database schema updates:"|bold}}
$ bee generate migration [migrationfile] [-fields="name:type"]
{{"To generate swagger doc file:"|bold}}
$ bee generate docs
{{"To generate a test case:"|bold}}
$ bee generate test [routerfile]
{{"To generate appcode based on an existing database:"|bold}}
$ bee generate appcode [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-level=3]
`,
PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() },
Run: generateCode,
}
var driver docValue
var conn docValue
var level docValue
var tables docValue
var fields docValue
func init() {
cmdGenerate.Flag.Var(&tables, "tables", "List of table names separated by a comma.")
cmdGenerate.Flag.Var(&driver, "driver", "Database driver. Either mysql, postgres or sqlite.")
cmdGenerate.Flag.Var(&conn, "conn", "Connection string used by the driver to connect to a database instance.")
cmdGenerate.Flag.Var(&level, "level", "Either 1, 2 or 3. i.e. 1=models; 2=models and controllers; 3=models, controllers and routers.")
cmdGenerate.Flag.Var(&fields, "fields", "List of table fields.")
}
func generateCode(cmd *Command, args []string) int {
currpath, _ := os.Getwd()
if len(args) < 1 {
logger.Fatal("Command is missing")
}
gps := GetGOPATHs()
if len(gps) == 0 {
logger.Fatal("GOPATH environment variable is not set or empty")
}
gopath := gps[0]
logger.Debugf("GOPATH: %s", __FILE__(), __LINE__(), gopath)
gcmd := args[0]
switch gcmd {
case "scaffold":
if len(args) < 2 {
logger.Fatal("Wrong number of arguments. Run: bee help generate")
}
// Load the configuration
err := loadConfig()
if err != nil {
logger.Fatalf("Failed to load configuration: %s", err)
}
cmd.Flag.Parse(args[2:])
if driver == "" {
driver = docValue(conf.Database.Driver)
if driver == "" {
driver = "mysql"
}
}
if conn == "" {
conn = docValue(conf.Database.Conn)
if conn == "" {
conn = "root:@tcp(127.0.0.1:3306)/test"
}
}
if fields == "" {
logger.Hint("fields option should not be empty, i.e. -fields=\"title:string,body:text\"")
logger.Fatal("Wrong number of arguments. Run: bee help generate")
}
sname := args[1]
generateScaffold(sname, fields.String(), currpath, driver.String(), conn.String())
case "docs":
generateDocs(currpath)
case "appcode":
// Load the configuration
err := loadConfig()
if err != nil {
logger.Fatalf("Failed to load configuration: %s", err)
}
cmd.Flag.Parse(args[1:])
if driver == "" {
driver = docValue(conf.Database.Driver)
if driver == "" {
driver = "mysql"
}
}
if conn == "" {
conn = docValue(conf.Database.Conn)
if conn == "" {
if driver == "mysql" {
conn = "root:@tcp(127.0.0.1:3306)/test"
} else if driver == "postgres" {
conn = "postgres://postgres:postgres@127.0.0.1:5432/postgres"
}
}
}
if level == "" {
level = "3"
}
logger.Infof("Using '%s' as 'driver'", driver)
logger.Infof("Using '%s' as 'conn'", conn)
logger.Infof("Using '%s' as 'tables'", tables)
logger.Infof("Using '%s' as 'level'", level)
generateAppcode(driver.String(), conn.String(), level.String(), tables.String(), currpath)
case "migration":
if len(args) < 2 {
logger.Fatal("Wrong number of arguments. Run: bee help generate")
}
cmd.Flag.Parse(args[2:])
mname := args[1]
logger.Infof("Using '%s' as migration name", mname)
upsql := ""
downsql := ""
if fields != "" {
dbMigrator := newDBDriver()
upsql = dbMigrator.generateCreateUp(mname)
downsql = dbMigrator.generateCreateDown(mname)
}
generateMigration(mname, upsql, downsql, currpath)
case "controller":
if len(args) == 2 {
cname := args[1]
generateController(cname, currpath)
} else {
logger.Fatal("Wrong number of arguments. Run: bee help generate")
}
case "model":
if len(args) < 2 {
logger.Fatal("Wrong number of arguments. Run: bee help generate")
}
cmd.Flag.Parse(args[2:])
if fields == "" {
logger.Hint("fields option should not be empty, i.e. -fields=\"title:string,body:text\"")
logger.Fatal("Wrong number of arguments. Run: bee help generate")
}
sname := args[1]
generateModel(sname, fields.String(), currpath)
case "view":
if len(args) == 2 {
cname := args[1]
generateView(cname, currpath)
} else {
logger.Fatal("Wrong number of arguments. Run: bee help generate")
}
default:
logger.Fatal("Command is missing")
}
logger.Successf("%s successfully generated!", strings.Title(gcmd))
return 0
}

View File

@ -1,48 +0,0 @@
package main
import "strings"
func generateScaffold(sname, fields, currpath, driver, conn string) {
logger.Infof("Do you want to create a '%s' model? [Yes|No] ", sname)
// Generate the model
if askForConfirmation() {
generateModel(sname, fields, currpath)
}
// Generate the controller
logger.Infof("Do you want to create a '%s' controller? [Yes|No] ", sname)
if askForConfirmation() {
generateController(sname, currpath)
}
// Generate the views
logger.Infof("Do you want to create views for this '%s' resource? [Yes|No] ", sname)
if askForConfirmation() {
generateView(sname, currpath)
}
// Generate a migration
logger.Infof("Do you want to create a '%s' migration and schema for this resource? [Yes|No] ", sname)
if askForConfirmation() {
upsql := ""
downsql := ""
if fields != "" {
dbMigrator := newDBDriver()
upsql = dbMigrator.generateCreateUp(sname)
downsql = dbMigrator.generateCreateDown(sname)
//todo remove
//if driver == "" {
// downsql = strings.Replace(downsql, "`", "", -1)
//}
}
generateMigration(sname, upsql, downsql, currpath)
}
// Run the migration
logger.Infof("Do you want to migrate the database? [Yes|No] ")
if askForConfirmation() {
migrateUpdate(currpath, driver, conn)
}
logger.Successf("All done! Don't forget to add beego.Router(\"/%s\" ,&controllers.%sController{}) to routers/route.go\n", sname, strings.Title(sname))
}

23
generate/g.go Normal file
View File

@ -0,0 +1,23 @@
// 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.
package generate
import "github.com/beego/bee/utils"
var SQLDriver utils.DocValue
var SQLConn utils.DocValue
var Level utils.DocValue
var Tables utils.DocValue
var Fields utils.DocValue

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"database/sql"
@ -23,6 +23,9 @@ import (
"regexp"
"strings"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
)
@ -183,7 +186,7 @@ type OrmTag struct {
// String returns the source code string for the Table struct
func (tb *Table) String() string {
rv := fmt.Sprintf("type %s struct {\n", camelCase(tb.Name))
rv := fmt.Sprintf("type %s struct {\n", utils.CamelCase(tb.Name))
for _, v := range tb.Columns {
rv += v.String() + "\n"
}
@ -255,7 +258,7 @@ func (tag *OrmTag) String() string {
return fmt.Sprintf("`orm:\"%s\"`", strings.Join(ormOptions, ";"))
}
func generateAppcode(driver, connStr, level, tables, currpath string) {
func GenerateAppcode(driver, connStr, level, tables, currpath string) {
var mode byte
switch level {
case "1":
@ -265,7 +268,7 @@ func generateAppcode(driver, connStr, level, tables, currpath string) {
case "3":
mode = OModel | OController | ORouter
default:
logger.Fatal("Invalid level value. Must be either \"1\", \"2\", or \"3\"")
beeLogger.Log.Fatal("Invalid level value. Must be either \"1\", \"2\", or \"3\"")
}
var selectedTables map[string]bool
if tables != "" {
@ -278,9 +281,9 @@ func generateAppcode(driver, connStr, level, tables, currpath string) {
case "mysql":
case "postgres":
case "sqlite":
logger.Fatal("Generating app code from SQLite database is not supported yet.")
beeLogger.Log.Fatal("Generating app code from SQLite database is not supported yet.")
default:
logger.Fatal("Unknown database driver. Must be either \"mysql\", \"postgres\" or \"sqlite\"")
beeLogger.Log.Fatal("Unknown database driver. Must be either \"mysql\", \"postgres\" or \"sqlite\"")
}
gen(driver, connStr, mode, selectedTables, currpath)
}
@ -290,11 +293,11 @@ func generateAppcode(driver, connStr, level, tables, currpath string) {
func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, apppath string) {
db, err := sql.Open(dbms, connStr)
if err != nil {
logger.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err)
beeLogger.Log.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err)
}
defer db.Close()
if trans, ok := dbDriver[dbms]; ok {
logger.Info("Analyzing database tables...")
beeLogger.Log.Info("Analyzing database tables...")
tableNames := trans.GetTableNames(db)
tables := getTableObjects(tableNames, db, trans)
mvcPath := new(MvcPath)
@ -305,7 +308,7 @@ func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, ap
pkgPath := getPackagePath(apppath)
writeSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames)
} else {
logger.Fatalf("Generating app code from '%s' database is not supported yet.", dbms)
beeLogger.Log.Fatalf("Generating app code from '%s' database is not supported yet.", dbms)
}
}
@ -313,13 +316,13 @@ func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, ap
func (*MysqlDB) GetTableNames(db *sql.DB) (tables []string) {
rows, err := db.Query("SHOW TABLES")
if err != nil {
logger.Fatalf("Could not show tables: %s", err)
beeLogger.Log.Fatalf("Could not show tables: %s", err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
logger.Fatalf("Could not show tables: %s", err)
beeLogger.Log.Fatalf("Could not show tables: %s", err)
}
tables = append(tables, name)
}
@ -362,12 +365,12 @@ func (*MysqlDB) GetConstraints(db *sql.DB, table *Table, blackList map[string]bo
c.table_schema = database() AND c.table_name = ? AND u.table_schema = database() AND u.table_name = ?`,
table.Name, table.Name) // u.position_in_unique_constraint,
if err != nil {
logger.Fatal("Could not query INFORMATION_SCHEMA for PK/UK/FK information")
beeLogger.Log.Fatal("Could not query INFORMATION_SCHEMA for PK/UK/FK information")
}
for rows.Next() {
var constraintTypeBytes, columnNameBytes, refTableSchemaBytes, refTableNameBytes, refColumnNameBytes, refOrdinalPosBytes []byte
if err := rows.Scan(&constraintTypeBytes, &columnNameBytes, &refTableSchemaBytes, &refTableNameBytes, &refColumnNameBytes, &refOrdinalPosBytes); err != nil {
logger.Fatal("Could not read INFORMATION_SCHEMA for PK/UK/FK information")
beeLogger.Log.Fatal("Could not read INFORMATION_SCHEMA for PK/UK/FK information")
}
constraintType, columnName, refTableSchema, refTableName, refColumnName, refOrdinalPos :=
string(constraintTypeBytes), string(columnNameBytes), string(refTableSchemaBytes),
@ -407,7 +410,7 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
table_schema = database() AND table_name = ?`,
table.Name)
if err != nil {
logger.Fatalf("Could not query the database: %s", err)
beeLogger.Log.Fatalf("Could not query the database: %s", err)
}
defer colDefRows.Close()
@ -415,17 +418,17 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
// datatype as bytes so that SQL <null> values can be retrieved
var colNameBytes, dataTypeBytes, columnTypeBytes, isNullableBytes, columnDefaultBytes, extraBytes []byte
if err := colDefRows.Scan(&colNameBytes, &dataTypeBytes, &columnTypeBytes, &isNullableBytes, &columnDefaultBytes, &extraBytes); err != nil {
logger.Fatal("Could not query INFORMATION_SCHEMA for column information")
beeLogger.Log.Fatal("Could not query INFORMATION_SCHEMA for column information")
}
colName, dataType, columnType, isNullable, columnDefault, extra :=
string(colNameBytes), string(dataTypeBytes), string(columnTypeBytes), string(isNullableBytes), string(columnDefaultBytes), string(extraBytes)
// create a column
col := new(Column)
col.Name = camelCase(colName)
col.Name = utils.CamelCase(colName)
col.Type, err = mysqlDB.GetGoDataType(dataType)
if err != nil {
logger.Fatalf("%s", err)
beeLogger.Log.Fatalf("%s", err)
}
// Tag info
@ -449,8 +452,8 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
if isFk && !isBl {
tag.RelFk = true
refStructName := fkCol.RefTable
col.Name = camelCase(colName)
col.Type = "*" + camelCase(refStructName)
col.Name = utils.CamelCase(colName)
col.Type = "*" + utils.CamelCase(refStructName)
} else {
// if the name of column is Id, and it's not primary key
if colName == "id" {
@ -464,7 +467,7 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
if sign == "unsigned" && extra != "auto_increment" {
col.Type, err = mysqlDB.GetGoDataType(dataType + " " + sign)
if err != nil {
logger.Fatalf("%s", err)
beeLogger.Log.Fatalf("%s", err)
}
}
}
@ -516,14 +519,14 @@ func (*PostgresDB) GetTableNames(db *sql.DB) (tables []string) {
table_type = 'BASE TABLE' AND
table_schema NOT IN ('pg_catalog', 'information_schema')`)
if err != nil {
logger.Fatalf("Could not show tables: %s", err)
beeLogger.Log.Fatalf("Could not show tables: %s", err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
logger.Fatalf("Could not show tables: %s", err)
beeLogger.Log.Fatalf("Could not show tables: %s", err)
}
tables = append(tables, name)
}
@ -553,13 +556,13 @@ func (*PostgresDB) GetConstraints(db *sql.DB, table *Table, blackList map[string
AND u.table_name = $2`,
table.Name, table.Name) // u.position_in_unique_constraint,
if err != nil {
logger.Fatalf("Could not query INFORMATION_SCHEMA for PK/UK/FK information: %s", err)
beeLogger.Log.Fatalf("Could not query INFORMATION_SCHEMA for PK/UK/FK information: %s", err)
}
for rows.Next() {
var constraintTypeBytes, columnNameBytes, refTableSchemaBytes, refTableNameBytes, refColumnNameBytes, refOrdinalPosBytes []byte
if err := rows.Scan(&constraintTypeBytes, &columnNameBytes, &refTableSchemaBytes, &refTableNameBytes, &refColumnNameBytes, &refOrdinalPosBytes); err != nil {
logger.Fatalf("Could not read INFORMATION_SCHEMA for PK/UK/FK information: %s", err)
beeLogger.Log.Fatalf("Could not read INFORMATION_SCHEMA for PK/UK/FK information: %s", err)
}
constraintType, columnName, refTableSchema, refTableName, refColumnName, refOrdinalPos :=
string(constraintTypeBytes), string(columnNameBytes), string(refTableSchemaBytes),
@ -609,7 +612,7 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map
AND table_name = $1`,
table.Name)
if err != nil {
logger.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err)
beeLogger.Log.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err)
}
defer colDefRows.Close()
@ -617,16 +620,16 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map
// datatype as bytes so that SQL <null> values can be retrieved
var colNameBytes, dataTypeBytes, columnTypeBytes, isNullableBytes, columnDefaultBytes, extraBytes []byte
if err := colDefRows.Scan(&colNameBytes, &dataTypeBytes, &columnTypeBytes, &isNullableBytes, &columnDefaultBytes, &extraBytes); err != nil {
logger.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err)
beeLogger.Log.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err)
}
colName, dataType, columnType, isNullable, columnDefault, extra :=
string(colNameBytes), string(dataTypeBytes), string(columnTypeBytes), string(isNullableBytes), string(columnDefaultBytes), string(extraBytes)
// Create a column
col := new(Column)
col.Name = camelCase(colName)
col.Name = utils.CamelCase(colName)
col.Type, err = postgresDB.GetGoDataType(dataType)
if err != nil {
logger.Fatalf("%s", err)
beeLogger.Log.Fatalf("%s", err)
}
// Tag info
@ -650,8 +653,8 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map
if isFk && !isBl {
tag.RelFk = true
refStructName := fkCol.RefTable
col.Name = camelCase(colName)
col.Type = "*" + camelCase(refStructName)
col.Name = utils.CamelCase(colName)
col.Type = "*" + utils.CamelCase(refStructName)
} else {
// if the name of column is Id, and it's not primary key
if colName == "id" {
@ -716,22 +719,22 @@ func createPaths(mode byte, paths *MvcPath) {
// Newly geneated files will be inside these folders.
func writeSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) {
if (OModel & mode) == OModel {
logger.Info("Creating model files...")
beeLogger.Log.Info("Creating model files...")
writeModelFiles(tables, paths.ModelPath, selectedTables)
}
if (OController & mode) == OController {
logger.Info("Creating controller files...")
beeLogger.Log.Info("Creating controller files...")
writeControllerFiles(tables, paths.ControllerPath, selectedTables, pkgPath)
}
if (ORouter & mode) == ORouter {
logger.Info("Creating router files...")
beeLogger.Log.Info("Creating router files...")
writeRouterFile(tables, paths.RouterPath, selectedTables, pkgPath)
}
}
// writeModelFiles generates model files
func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bool) {
w := NewColorWriter(os.Stdout)
w := colors.NewColorWriter(os.Stdout)
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
@ -744,22 +747,22 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo
fpath := path.Join(mPath, filename+".go")
var f *os.File
var err error
if isExist(fpath) {
logger.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
if utils.IsExist(fpath) {
beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if utils.AskForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
logger.Warnf("%s", err)
beeLogger.Log.Warnf("%s", err)
continue
}
} else {
logger.Warnf("Skipped create file '%s'", fpath)
beeLogger.Log.Warnf("Skipped create file '%s'", fpath)
continue
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
logger.Warnf("%s", err)
beeLogger.Log.Warnf("%s", err)
continue
}
}
@ -770,7 +773,7 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo
template = ModelTPL
}
fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1)
fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{modelName}}", utils.CamelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{tableName}}", tb.Name, -1)
// If table contains time field, import time.Time package
@ -783,17 +786,17 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo
fileStr = strings.Replace(fileStr, "{{timePkg}}", timePkg, -1)
fileStr = strings.Replace(fileStr, "{{importTimePkg}}", importTimePkg, -1)
if _, err := f.WriteString(fileStr); err != nil {
logger.Fatalf("Could not write model file to '%s': %s", fpath, err)
beeLogger.Log.Fatalf("Could not write model file to '%s': %s", fpath, err)
}
CloseFile(f)
utils.CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
}
}
// writeControllerFiles generates controller files
func writeControllerFiles(tables []*Table, cPath string, selectedTables map[string]bool, pkgPath string) {
w := NewColorWriter(os.Stdout)
w := colors.NewColorWriter(os.Stdout)
for _, tb := range tables {
// If selectedTables map is not nil and this table is not selected, ignore it
@ -809,39 +812,39 @@ func writeControllerFiles(tables []*Table, cPath string, selectedTables map[stri
fpath := path.Join(cPath, filename+".go")
var f *os.File
var err error
if isExist(fpath) {
logger.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
if utils.IsExist(fpath) {
beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if utils.AskForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
logger.Warnf("%s", err)
beeLogger.Log.Warnf("%s", err)
continue
}
} else {
logger.Warnf("Skipped create file '%s'", fpath)
beeLogger.Log.Warnf("Skipped create file '%s'", fpath)
continue
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
logger.Warnf("%s", err)
beeLogger.Log.Warnf("%s", err)
continue
}
}
fileStr := strings.Replace(CtrlTPL, "{{ctrlName}}", camelCase(tb.Name), -1)
fileStr := strings.Replace(CtrlTPL, "{{ctrlName}}", utils.CamelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{pkgPath}}", pkgPath, -1)
if _, err := f.WriteString(fileStr); err != nil {
logger.Fatalf("Could not write controller file to '%s': %s", fpath, err)
beeLogger.Log.Fatalf("Could not write controller file to '%s': %s", fpath, err)
}
CloseFile(f)
utils.CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
}
}
// writeRouterFile generates router file
func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bool, pkgPath string) {
w := NewColorWriter(os.Stdout)
w := colors.NewColorWriter(os.Stdout)
var nameSpaces []string
for _, tb := range tables {
@ -856,7 +859,7 @@ func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bo
}
// Add namespaces
nameSpace := strings.Replace(NamespaceTPL, "{{nameSpace}}", tb.Name, -1)
nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", camelCase(tb.Name), -1)
nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", utils.CamelCase(tb.Name), -1)
nameSpaces = append(nameSpaces, nameSpace)
}
// Add export controller
@ -865,31 +868,31 @@ func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bo
routerStr = strings.Replace(routerStr, "{{pkgPath}}", pkgPath, 1)
var f *os.File
var err error
if isExist(fpath) {
logger.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
if utils.IsExist(fpath) {
beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if utils.AskForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
logger.Warnf("%s", err)
beeLogger.Log.Warnf("%s", err)
return
}
} else {
logger.Warnf("Skipped create file '%s'", fpath)
beeLogger.Log.Warnf("Skipped create file '%s'", fpath)
return
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
logger.Warnf("%s", err)
beeLogger.Log.Warnf("%s", err)
return
}
}
if _, err := f.WriteString(routerStr); err != nil {
logger.Fatalf("Could not write router file to '%s': %s", fpath, err)
beeLogger.Log.Fatalf("Could not write router file to '%s': %s", fpath, err)
}
CloseFile(f)
utils.CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
}
func isSQLTemporalType(t string) bool {
@ -952,10 +955,10 @@ func getFileName(tbName string) (filename string) {
func getPackagePath(curpath string) (packpath string) {
gopath := os.Getenv("GOPATH")
if gopath == "" {
logger.Fatal("GOPATH environment variable is not set or empty")
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
logger.Debugf("GOPATH: %s", __FILE__(), __LINE__(), gopath)
beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath)
appsrcpath := ""
haspath := false
@ -964,7 +967,7 @@ func getPackagePath(curpath string) (packpath string) {
for _, wg := range wgopath {
wg, _ = filepath.EvalSymlinks(path.Join(wg, "src"))
if filepath.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
haspath = true
appsrcpath = wg
break
@ -972,11 +975,11 @@ func getPackagePath(curpath string) (packpath string) {
}
if !haspath {
logger.Fatalf("Cannot generate application code outside of GOPATH '%s'", gopath)
beeLogger.Log.Fatalf("Cannot generate application code outside of GOPATH '%s'", gopath)
}
if curpath == appsrcpath {
logger.Fatal("Cannot generate application code outside of application path")
beeLogger.Log.Fatal("Cannot generate application code outside of application path")
}
packpath = strings.Join(strings.Split(curpath[len(appsrcpath)+1:], string(filepath.Separator)), "/")

View File

@ -12,17 +12,21 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"fmt"
"os"
"path"
"strings"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
)
func generateController(cname, currpath string) {
w := NewColorWriter(os.Stdout)
func GenerateController(cname, currpath string) {
w := colors.NewColorWriter(os.Stdout)
p, f := path.Split(cname)
controllerName := strings.Title(f)
@ -33,26 +37,26 @@ func generateController(cname, currpath string) {
packageName = p[i+1 : len(p)-1]
}
logger.Infof("Using '%s' as controller name", controllerName)
logger.Infof("Using '%s' as package name", packageName)
beeLogger.Log.Infof("Using '%s' as controller name", controllerName)
beeLogger.Log.Infof("Using '%s' as package name", packageName)
fp := path.Join(currpath, "controllers", p)
if _, err := os.Stat(fp); os.IsNotExist(err) {
// Create the controller's directory
if err := os.MkdirAll(fp, 0777); err != nil {
logger.Fatalf("Could not create controllers directory: %s", err)
beeLogger.Log.Fatalf("Could not create controllers directory: %s", err)
}
}
fpath := path.Join(fp, strings.ToLower(controllerName)+".go")
if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
modelPath := path.Join(currpath, "models", strings.ToLower(controllerName)+".go")
var content string
if _, err := os.Stat(modelPath); err == nil {
logger.Infof("Using matching model '%s'", controllerName)
beeLogger.Log.Infof("Using matching model '%s'", controllerName)
content = strings.Replace(controllerModelTpl, "{{packageName}}", packageName, -1)
pkgPath := getPackagePath(currpath)
content = strings.Replace(content, "{{pkgPath}}", pkgPath, -1)
@ -64,10 +68,10 @@ func generateController(cname, currpath string) {
f.WriteString(content)
// Run 'gofmt' on the generated source code
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
} else {
logger.Fatalf("Could not create controller file: %s", err)
beeLogger.Log.Fatalf("Could not create controller file: %s", err)
}
}

View File

@ -15,7 +15,7 @@
* *
\**********************************************************/
package main
package generate
import (
"database/sql"
@ -24,11 +24,256 @@ import (
"path"
"strings"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
)
func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
var Hproseconf = `appname = {{.Appname}}
httpport = 8080
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
`
var HproseMaingo = `package main
import (
"fmt"
"reflect"
"{{.Appname}}/models"
"github.com/hprose/hprose-golang/rpc"
"github.com/astaxie/beego"
)
func logInvokeHandler(
name string,
args []reflect.Value,
context rpc.Context,
next rpc.NextInvokeHandler) (results []reflect.Value, err error) {
fmt.Printf("%s(%v) = ", name, args)
results, err = next(name, args, context)
fmt.Printf("%v %v\r\n", results, err)
return
}
func main() {
// Create WebSocketServer
// service := rpc.NewWebSocketService()
// Create Http Server
service := rpc.NewHTTPService()
// Use Logger Middleware
service.AddInvokeHandler(logInvokeHandler)
// Publish Functions
service.AddFunction("AddOne", models.AddOne)
service.AddFunction("GetOne", models.GetOne)
// Start Service
beego.Handler("/", service)
beego.Run()
}
`
var HproseMainconngo = `package main
import (
"fmt"
"reflect"
"{{.Appname}}/models"
"github.com/hprose/hprose-golang/rpc"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
{{.DriverPkg}}
)
func init() {
orm.RegisterDataBase("default", "{{.DriverName}}", "{{.conn}}")
}
func logInvokeHandler(
name string,
args []reflect.Value,
context rpc.Context,
next rpc.NextInvokeHandler) (results []reflect.Value, err error) {
fmt.Printf("%s(%v) = ", name, args)
results, err = next(name, args, context)
fmt.Printf("%v %v\r\n", results, err)
return
}
func main() {
// Create WebSocketServer
// service := rpc.NewWebSocketService()
// Create Http Server
service := rpc.NewHTTPService()
// Use Logger Middleware
service.AddInvokeHandler(logInvokeHandler)
{{HproseFunctionList}}
// Start Service
beego.Handler("/", service)
beego.Run()
}
`
var HproseModels = `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)
}
`
var HproseModels2 = `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)
}
`
var HproseAddFunctions = []string{}
func GenerateHproseAppcode(driver, connStr, level, tables, currpath string) {
var mode byte
switch level {
case "1":
@ -38,7 +283,7 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
case "3":
mode = OModel | OController | ORouter
default:
logger.Fatal("Invalid 'level' option. Level must be either \"1\", \"2\" or \"3\"")
beeLogger.Log.Fatal("Invalid 'level' option. Level must be either \"1\", \"2\" or \"3\"")
}
var selectedTables map[string]bool
if tables != "" {
@ -51,9 +296,9 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
case "mysql":
case "postgres":
case "sqlite":
logger.Fatal("Generating app code from SQLite database is not supported yet")
beeLogger.Log.Fatal("Generating app code from SQLite database is not supported yet")
default:
logger.Fatalf("Unknown database driver '%s'. Driver must be one of mysql, postgres or sqlite", driver)
beeLogger.Log.Fatalf("Unknown database driver '%s'. Driver must be one of mysql, postgres or sqlite", driver)
}
genHprose(driver, connStr, mode, selectedTables, currpath)
}
@ -63,11 +308,11 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bool, currpath string) {
db, err := sql.Open(dbms, connStr)
if err != nil {
logger.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err)
beeLogger.Log.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err)
}
defer db.Close()
if trans, ok := dbDriver[dbms]; ok {
logger.Info("Analyzing database tables...")
beeLogger.Log.Info("Analyzing database tables...")
tableNames := trans.GetTableNames(db)
tables := getTableObjects(tableNames, db, trans)
mvcPath := new(MvcPath)
@ -76,7 +321,7 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo
pkgPath := getPackagePath(currpath)
writeHproseSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames)
} else {
logger.Fatalf("Generating app code from '%s' database is not supported yet", dbms)
beeLogger.Log.Fatalf("Generating app code from '%s' database is not supported yet", dbms)
}
}
@ -85,14 +330,14 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo
// Newly geneated files will be inside these folders.
func writeHproseSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) {
if (OModel & mode) == OModel {
logger.Info("Creating model files...")
beeLogger.Log.Info("Creating model files...")
writeHproseModelFiles(tables, paths.ModelPath, selectedTables)
}
}
// writeHproseModelFiles generates model files
func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[string]bool) {
w := NewColorWriter(os.Stdout)
w := colors.NewColorWriter(os.Stdout)
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
@ -105,22 +350,22 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str
fpath := path.Join(mPath, filename+".go")
var f *os.File
var err error
if isExist(fpath) {
logger.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
if utils.IsExist(fpath) {
beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if utils.AskForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
logger.Warnf("%s", err)
beeLogger.Log.Warnf("%s", err)
continue
}
} else {
logger.Warnf("Skipped create file '%s'", fpath)
beeLogger.Log.Warnf("Skipped create file '%s'", fpath)
continue
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
logger.Warnf("%s", err)
beeLogger.Log.Warnf("%s", err)
continue
}
}
@ -129,10 +374,10 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str
template = HproseStructModelTPL
} else {
template = HproseModelTPL
hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HproseAddFunction, "{{modelName}}", camelCase(tb.Name), -1))
HproseAddFunctions = append(HproseAddFunctions, strings.Replace(HproseAddFunction, "{{modelName}}", utils.CamelCase(tb.Name), -1))
}
fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1)
fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{modelName}}", utils.CamelCase(tb.Name), -1)
// if table contains time field, import time.Time package
timePkg := ""
importTimePkg := ""
@ -143,11 +388,11 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str
fileStr = strings.Replace(fileStr, "{{timePkg}}", timePkg, -1)
fileStr = strings.Replace(fileStr, "{{importTimePkg}}", importTimePkg, -1)
if _, err := f.WriteString(fileStr); err != nil {
logger.Fatalf("Could not write model file to '%s'", fpath)
beeLogger.Log.Fatalf("Could not write model file to '%s'", fpath)
}
CloseFile(f)
utils.CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
}
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"fmt"
@ -20,6 +20,10 @@ import (
"path"
"strings"
"time"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
)
const (
@ -29,18 +33,18 @@ const (
)
type DBDriver interface {
generateCreateUp(tableName string) string
generateCreateDown(tableName string) string
GenerateCreateUp(tableName string) string
GenerateCreateDown(tableName string) string
}
type mysqlDriver struct{}
func (m mysqlDriver) generateCreateUp(tableName string) string {
upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(fields.String()) + `)");`
func (m mysqlDriver) GenerateCreateUp(tableName string) string {
upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(Fields.String()) + `)");`
return upsql
}
func (m mysqlDriver) generateCreateDown(tableName string) string {
func (m mysqlDriver) GenerateCreateDown(tableName string) string {
downsql := `m.SQL("DROP TABLE ` + "`" + tableName + "`" + `")`
return downsql
}
@ -51,21 +55,21 @@ func (m mysqlDriver) generateSQLFromFields(fields string) string {
for i, v := range fds {
kv := strings.SplitN(v, ":", 2)
if len(kv) != 2 {
logger.Error("Fields format is wrong. Should be: key:type,key:type " + v)
beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v)
return ""
}
typ, tag := m.getSQLType(kv[1])
if typ == "" {
logger.Error("Fields format is wrong. Should be: key:type,key:type " + v)
beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v)
return ""
}
if i == 0 && strings.ToLower(kv[0]) != "id" {
sql += "`id` int(11) NOT NULL AUTO_INCREMENT,"
tags = tags + "PRIMARY KEY (`id`),"
}
sql += "`" + snakeString(kv[0]) + "` " + typ + ","
sql += "`" + utils.SnakeString(kv[0]) + "` " + typ + ","
if tag != "" {
tags = tags + fmt.Sprintf(tag, "`"+snakeString(kv[0])+"`") + ","
tags = tags + fmt.Sprintf(tag, "`"+utils.SnakeString(kv[0])+"`") + ","
}
}
sql = strings.TrimRight(sql+tags, ",")
@ -104,12 +108,12 @@ func (m mysqlDriver) getSQLType(ktype string) (tp, tag string) {
type postgresqlDriver struct{}
func (m postgresqlDriver) generateCreateUp(tableName string) string {
upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(fields.String()) + `)");`
func (m postgresqlDriver) GenerateCreateUp(tableName string) string {
upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(Fields.String()) + `)");`
return upsql
}
func (m postgresqlDriver) generateCreateDown(tableName string) string {
func (m postgresqlDriver) GenerateCreateDown(tableName string) string {
downsql := `m.SQL("DROP TABLE ` + tableName + `")`
return downsql
}
@ -120,20 +124,20 @@ func (m postgresqlDriver) generateSQLFromFields(fields string) string {
for i, v := range fds {
kv := strings.SplitN(v, ":", 2)
if len(kv) != 2 {
logger.Error("Fields format is wrong. Should be: key:type,key:type " + v)
beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v)
return ""
}
typ, tag := m.getSQLType(kv[1])
if typ == "" {
logger.Error("Fields format is wrong. Should be: key:type,key:type " + v)
beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v)
return ""
}
if i == 0 && strings.ToLower(kv[0]) != "id" {
sql += "id serial primary key,"
}
sql += snakeString(kv[0]) + " " + typ + ","
sql += utils.SnakeString(kv[0]) + " " + typ + ","
if tag != "" {
tags = tags + fmt.Sprintf(tag, snakeString(kv[0])) + ","
tags = tags + fmt.Sprintf(tag, utils.SnakeString(kv[0])) + ","
}
}
if tags != "" {
@ -170,14 +174,14 @@ func (m postgresqlDriver) getSQLType(ktype string) (tp, tag string) {
return "", ""
}
func newDBDriver() DBDriver {
switch driver {
func NewDBDriver() DBDriver {
switch SQLDriver {
case "mysql":
return mysqlDriver{}
case "postgres":
return postgresqlDriver{}
default:
logger.Fatal("Driver not supported")
beeLogger.Log.Fatal("Driver not supported")
return nil
}
}
@ -185,30 +189,30 @@ func newDBDriver() DBDriver {
// generateMigration generates migration file template for database schema update.
// The generated file template consists of an up() method for updating schema and
// a down() method for reverting the update.
func generateMigration(mname, upsql, downsql, curpath string) {
w := NewColorWriter(os.Stdout)
func GenerateMigration(mname, upsql, downsql, curpath string) {
w := colors.NewColorWriter(os.Stdout)
migrationFilePath := path.Join(curpath, DBPath, MPath)
if _, err := os.Stat(migrationFilePath); os.IsNotExist(err) {
// create migrations directory
if err := os.MkdirAll(migrationFilePath, 0777); err != nil {
logger.Fatalf("Could not create migration directory: %s", err)
beeLogger.Log.Fatalf("Could not create migration directory: %s", err)
}
}
// create file
today := time.Now().Format(MDateFormat)
fpath := path.Join(migrationFilePath, fmt.Sprintf("%s_%s.go", today, mname))
if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
content := strings.Replace(MigrationTPL, "{{StructName}}", camelCase(mname)+"_"+today, -1)
defer utils.CloseFile(f)
content := strings.Replace(MigrationTPL, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
content = strings.Replace(content, "{{CurrTime}}", today, -1)
content = strings.Replace(content, "{{UpSQL}}", upsql, -1)
content = strings.Replace(content, "{{DownSQL}}", downsql, -1)
f.WriteString(content)
// Run 'gofmt' on the generated source code
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
} else {
logger.Fatalf("Could not create migration file: %s", err)
beeLogger.Log.Fatalf("Could not create migration file: %s", err)
}
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"errors"
@ -20,10 +20,14 @@ import (
"os"
"path"
"strings"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
)
func generateModel(mname, fields, currpath string) {
w := NewColorWriter(os.Stdout)
func GenerateModel(mname, fields, currpath string) {
w := colors.NewColorWriter(os.Stdout)
p, f := path.Split(mname)
modelName := strings.Title(f)
@ -35,23 +39,23 @@ func generateModel(mname, fields, currpath string) {
modelStruct, hastime, err := getStruct(modelName, fields)
if err != nil {
logger.Fatalf("Could not generate the model struct: %s", err)
beeLogger.Log.Fatalf("Could not generate the model struct: %s", err)
}
logger.Infof("Using '%s' as model name", modelName)
logger.Infof("Using '%s' as package name", packageName)
beeLogger.Log.Infof("Using '%s' as model name", modelName)
beeLogger.Log.Infof("Using '%s' as package name", packageName)
fp := path.Join(currpath, "models", p)
if _, err := os.Stat(fp); os.IsNotExist(err) {
// Create the model's directory
if err := os.MkdirAll(fp, 0777); err != nil {
logger.Fatalf("Could not create the model directory: %s", err)
beeLogger.Log.Fatalf("Could not create the model directory: %s", err)
}
}
fpath := path.Join(fp, strings.ToLower(modelName)+".go")
if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
content := strings.Replace(modelTpl, "{{packageName}}", packageName, -1)
content = strings.Replace(content, "{{modelName}}", modelName, -1)
content = strings.Replace(content, "{{modelStruct}}", modelStruct, -1)
@ -62,10 +66,10 @@ func generateModel(mname, fields, currpath string) {
}
f.WriteString(content)
// Run 'gofmt' on the generated source code
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
} else {
logger.Fatalf("Could not create model file: %s", err)
beeLogger.Log.Fatalf("Could not create model file: %s", err)
}
}
@ -95,7 +99,7 @@ func getStruct(structname, fields string) (string, bool, error) {
if hastimeinner {
hastime = true
}
structStr = structStr + camelString(kv[0]) + " " + typ + " " + tag + "\n"
structStr = structStr + utils.CamelString(kv[0]) + " " + typ + " " + tag + "\n"
}
structStr += "}\n"
return structStr, hastime, nil

50
generate/g_scaffold.go Normal file
View File

@ -0,0 +1,50 @@
package generate
import (
"strings"
"github.com/beego/bee/cmd/commands/migrate"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
)
func GenerateScaffold(sname, fields, currpath, driver, conn string) {
beeLogger.Log.Infof("Do you want to create a '%s' model? [Yes|No] ", sname)
// Generate the model
if utils.AskForConfirmation() {
GenerateModel(sname, fields, currpath)
}
// Generate the controller
beeLogger.Log.Infof("Do you want to create a '%s' controller? [Yes|No] ", sname)
if utils.AskForConfirmation() {
GenerateController(sname, currpath)
}
// Generate the views
beeLogger.Log.Infof("Do you want to create views for this '%s' resource? [Yes|No] ", sname)
if utils.AskForConfirmation() {
GenerateView(sname, currpath)
}
// Generate a migration
beeLogger.Log.Infof("Do you want to create a '%s' migration and schema for this resource? [Yes|No] ", sname)
if utils.AskForConfirmation() {
upsql := ""
downsql := ""
if fields != "" {
dbMigrator := NewDBDriver()
upsql = dbMigrator.GenerateCreateUp(sname)
downsql = dbMigrator.GenerateCreateDown(sname)
}
GenerateMigration(sname, upsql, downsql, currpath)
}
// Run the migration
beeLogger.Log.Infof("Do you want to migrate the database? [Yes|No] ")
if utils.AskForConfirmation() {
migrate.MigrateUpdate(currpath, driver, conn)
}
beeLogger.Log.Successf("All done! Don't forget to add beego.Router(\"/%s\" ,&controllers.%sController{}) to routers/route.go\n", sname, strings.Title(sname))
}

View File

@ -12,60 +12,64 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"fmt"
"os"
"path"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
)
// recipe
// admin/recipe
func generateView(viewpath, currpath string) {
w := NewColorWriter(os.Stdout)
func GenerateView(viewpath, currpath string) {
w := colors.NewColorWriter(os.Stdout)
logger.Info("Generating view...")
beeLogger.Log.Info("Generating view...")
absViewPath := path.Join(currpath, "views", viewpath)
err := os.MkdirAll(absViewPath, os.ModePerm)
if err != nil {
logger.Fatalf("Could not create '%s' view: %s", viewpath, err)
beeLogger.Log.Fatalf("Could not create '%s' view: %s", viewpath, err)
}
cfile := path.Join(absViewPath, "index.tpl")
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
f.WriteString(cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
logger.Fatalf("Could not create view file: %s", err)
beeLogger.Log.Fatalf("Could not create view file: %s", err)
}
cfile = path.Join(absViewPath, "show.tpl")
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
f.WriteString(cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
logger.Fatalf("Could not create view file: %s", err)
beeLogger.Log.Fatalf("Could not create view file: %s", err)
}
cfile = path.Join(absViewPath, "create.tpl")
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
f.WriteString(cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
logger.Fatalf("Could not create view file: %s", err)
beeLogger.Log.Fatalf("Could not create view file: %s", err)
}
cfile = path.Join(absViewPath, "edit.tpl")
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
f.WriteString(cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
logger.Fatalf("Could not create view file: %s", err)
beeLogger.Log.Fatalf("Could not create view file: %s", err)
}
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package swaggergen
import (
"encoding/json"
@ -35,6 +35,7 @@ import (
"github.com/astaxie/beego/swagger"
"github.com/astaxie/beego/utils"
beeLogger "github.com/beego/bee/logger"
)
const (
@ -90,7 +91,7 @@ func init() {
astPkgs = map[string]*ast.Package{}
}
func parsePackagesFromDir(dirpath string) {
func ParsePackagesFromDir(dirpath string) {
c := make(chan error)
go func() {
@ -116,7 +117,7 @@ func parsePackagesFromDir(dirpath string) {
}()
for err := range c {
logger.Warnf("%s", err)
beeLogger.Log.Warnf("%s", err)
}
}
@ -137,12 +138,12 @@ func parsePackageFromDir(path string) error {
return nil
}
func generateDocs(curpath string) {
func GenerateDocs(curpath string) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path.Join(curpath, "routers", "router.go"), nil, parser.ParseComments)
if err != nil {
logger.Fatalf("Error while parsing router.go: %s", err)
// beeLogger.Log.Fatalf("Error while parsing router.go: %s", err)
}
rootapi.Infos = swagger.Information{}
@ -251,6 +252,9 @@ func generateDocs(curpath string) {
}
os.Mkdir(path.Join(curpath, "swagger"), 0755)
fd, err := os.Create(path.Join(curpath, "swagger", "swagger.json"))
if err != nil {
panic(err)
}
fdyml, err := os.Create(path.Join(curpath, "swagger", "swagger.yml"))
if err != nil {
panic(err)
@ -348,7 +352,7 @@ func analyseControllerPkg(localName, pkgpath string) {
}
gopath := os.Getenv("GOPATH")
if gopath == "" {
logger.Fatal("GOPATH environment variable is not set or empty")
// beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
pkgRealpath := ""
@ -366,7 +370,7 @@ func analyseControllerPkg(localName, pkgpath string) {
}
pkgCache[pkgpath] = struct{}{}
} else {
logger.Fatalf("Package '%s' does not exist in the GOPATH", pkgpath)
// beeLogger.Log.Fatalf("Package '%s' does not exist in the GOPATH", pkgpath)
}
fileSet := token.NewFileSet()
@ -375,7 +379,7 @@ func analyseControllerPkg(localName, pkgpath string) {
return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}, parser.ParseComments)
if err != nil {
logger.Fatalf("Error while parsing dir at '%s': %s", pkgpath, err)
// beeLogger.Log.Fatalf("Error while parsing dir at '%s': %s", pkgpath, err)
}
for _, pkg := range astPkgs {
for _, fl := range pkg.Files {
@ -413,7 +417,7 @@ func isSystemPackage(pkgpath string) bool {
goroot = runtime.GOROOT()
}
if goroot == "" {
logger.Fatalf("GOROOT environment variable is not set or empty")
// beeLogger.Log.Fatalf("GOROOT environment variable is not set or empty")
}
wg, _ := filepath.EvalSymlinks(filepath.Join(goroot, "src", "pkg", pkgpath))
@ -423,11 +427,7 @@ func isSystemPackage(pkgpath string) bool {
//TODO(zh):support go1.4
wg, _ = filepath.EvalSymlinks(filepath.Join(goroot, "src", pkgpath))
if utils.FileExists(wg) {
return true
}
return false
return utils.FileExists(wg)
}
func peekNextSplitString(ss string) (s string, spacePos int) {
@ -481,7 +481,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
ss = strings.TrimSpace(ss[pos:])
schemaName, pos := peekNextSplitString(ss)
if schemaName == "" {
logger.Fatalf("[%s.%s] Schema must follow {object} or {array}", controllerName, funcName)
// beeLogger.Log.Fatalf("[%s.%s] Schema must follow {object} or {array}", controllerName, funcName)
}
if strings.HasPrefix(schemaName, "[]") {
schemaName = schemaName[2:]
@ -496,7 +496,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
m, mod, realTypes := getModel(schemaName)
schema.Ref = "#/definitions/" + m
if _, ok := modelsList[pkgpath+controllerName]; !ok {
modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema, 0)
modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema)
}
modelsList[pkgpath+controllerName][schemaName] = mod
appendModels(pkgpath, controllerName, realTypes)
@ -518,7 +518,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
para := swagger.Parameter{}
p := getparams(strings.TrimSpace(t[len("@Param "):]))
if len(p) < 4 {
logger.Fatal(controllerName + "_" + funcName + "'s comments @Param should have at least 4 params")
// beeLogger.Log.Fatal(controllerName + "_" + funcName + "'s comments @Param should have at least 4 params")
}
para.Name = p[0]
switch p[1] {
@ -533,7 +533,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
case "body":
break
default:
logger.Warnf("[%s.%s] Unknown param location: %s. Possible values are `query`, `header`, `path`, `formData` or `body`.\n", controllerName, funcName, p[1])
// beeLogger.Log.Warnf("[%s.%s] Unknown param location: %s. Possible values are `query`, `header`, `path`, `formData` or `body`.\n", controllerName, funcName, p[1])
}
para.In = p[1]
pp := strings.Split(p[2], ".")
@ -544,7 +544,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
Ref: "#/definitions/" + m,
}
if _, ok := modelsList[pkgpath+controllerName]; !ok {
modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema, 0)
modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema)
}
modelsList[pkgpath+controllerName][typ] = mod
appendModels(pkgpath, controllerName, realTypes)
@ -564,7 +564,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
paraType = typeFormat[0]
paraFormat = typeFormat[1]
} else {
logger.Warnf("[%s.%s] Unknown param type: %s\n", controllerName, funcName, typ)
// beeLogger.Log.Warnf("[%s.%s] Unknown param type: %s\n", controllerName, funcName, typ)
}
if isArray {
para.Type = "array"
@ -717,7 +717,7 @@ func getModel(str string) (objectname string, m swagger.Schema, realTypes []stri
}
}
if m.Title == "" {
logger.Warnf("Cannot find the object: %s", str)
// beeLogger.Log.Warnf("Cannot find the object: %s", str)
// TODO remove when all type have been supported
//os.Exit(1)
}
@ -732,7 +732,7 @@ func getModel(str string) (objectname string, m swagger.Schema, realTypes []stri
func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string, astPkgs map[string]*ast.Package, packageName string) {
ts, ok := d.Decl.(*ast.TypeSpec)
if !ok {
logger.Fatalf("Unknown type without TypeSec: %v\n", d)
// beeLogger.Log.Fatalf("Unknown type without TypeSec: %v\n", d)
}
// TODO support other types, such as `ArrayType`, `MapType`, `InterfaceType` etc...
st, ok := ts.Type.(*ast.StructType)
@ -808,7 +808,7 @@ func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string
mp.Default = str2RealType(res[1], realType)
} else {
logger.Warnf("Invalid default value: %s", defaultValue)
// beeLogger.Log.Warnf("Invalid default value: %s", defaultValue)
}
}
@ -899,16 +899,6 @@ func isBasicType(Type string) bool {
return false
}
// regexp get json tag
func grepJSONTag(tag string) string {
r, _ := regexp.Compile(`json:"([^"]*)"`)
matches := r.FindAllStringSubmatch(tag, -1)
if len(matches) > 0 {
return matches[0][1]
}
return ""
}
// append models
func appendModels(pkgpath, controllerName string, realTypes []string) {
for _, realType := range realTypes {
@ -956,7 +946,7 @@ func str2RealType(s string, typ string) interface{} {
}
if err != nil {
logger.Warnf("Invalid default value type '%s': %s", typ, s)
// beeLogger.Log.Warnf("Invalid default value type '%s': %s", typ, s)
return s
}

View File

@ -1,369 +0,0 @@
// 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.
package main
import (
"fmt"
"os"
path "path/filepath"
"strings"
)
var cmdHproseapp = &Command{
// CustomFlags: true,
UsageLine: "hprose [appname]",
Short: "Creates an RPC application based on Hprose and Beego frameworks",
Long: `
The command 'hprose' creates an RPC application based on both Beego and Hprose (http://hprose.com/).
{{"To scaffold out your application, use:"|bold}}
$ bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test]
If 'conn' is empty, the command will generate a sample application. Otherwise the command
will connect to your database and generate models based on the existing tables.
The command 'hprose' creates a folder named [appname] with the following structure:
main.go
{{"conf"|foldername}}
app.conf
{{"models"|foldername}}
object.go
user.go
`,
PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() },
Run: createhprose,
}
var hproseconf = `appname = {{.Appname}}
httpport = 8080
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
`
var hproseMaingo = `package main
import (
"fmt"
"reflect"
"{{.Appname}}/models"
"github.com/hprose/hprose-golang/rpc"
"github.com/astaxie/beego"
)
func logInvokeHandler(
name string,
args []reflect.Value,
context rpc.Context,
next rpc.NextInvokeHandler) (results []reflect.Value, err error) {
fmt.Printf("%s(%v) = ", name, args)
results, err = next(name, args, context)
fmt.Printf("%v %v\r\n", results, err)
return
}
func main() {
// Create WebSocketServer
// service := rpc.NewWebSocketService()
// Create Http Server
service := rpc.NewHTTPService()
// Use Logger Middleware
service.AddInvokeHandler(logInvokeHandler)
// Publish Functions
service.AddFunction("AddOne", models.AddOne)
service.AddFunction("GetOne", models.GetOne)
// Start Service
beego.Handler("/", service)
beego.Run()
}
`
var hproseMainconngo = `package main
import (
"fmt"
"reflect"
"{{.Appname}}/models"
"github.com/hprose/hprose-golang/rpc"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
{{.DriverPkg}}
)
func init() {
orm.RegisterDataBase("default", "{{.DriverName}}", "{{.conn}}")
}
func logInvokeHandler(
name string,
args []reflect.Value,
context rpc.Context,
next rpc.NextInvokeHandler) (results []reflect.Value, err error) {
fmt.Printf("%s(%v) = ", name, args)
results, err = next(name, args, context)
fmt.Printf("%v %v\r\n", results, err)
return
}
func main() {
// Create WebSocketServer
// service := rpc.NewWebSocketService()
// Create Http Server
service := rpc.NewHTTPService()
// Use Logger Middleware
service.AddInvokeHandler(logInvokeHandler)
{{HproseFunctionList}}
// Start Service
beego.Handler("/", service)
beego.Run()
}
`
var hproseModels = `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)
}
`
var hproseModels2 = `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)
}
`
var hproseAddFunctions = []string{}
func init() {
cmdHproseapp.Flag.Var(&tables, "tables", "List of table names separated by a comma.")
cmdHproseapp.Flag.Var(&driver, "driver", "Database driver. Either mysql, postgres or sqlite.")
cmdHproseapp.Flag.Var(&conn, "conn", "Connection string used by the driver to connect to a database instance.")
}
func createhprose(cmd *Command, args []string) int {
output := cmd.Out()
if len(args) != 1 {
logger.Fatal("Argument [appname] is missing")
}
curpath, _ := os.Getwd()
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
}
apppath, packpath, err := checkEnv(args[0])
if err != nil {
logger.Fatalf("%s", err)
}
if driver == "" {
driver = "mysql"
}
if conn == "" {
}
logger.Info("Creating Hprose application...")
os.MkdirAll(apppath, 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath, "\x1b[0m")
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m")
WriteToFile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(hproseconf, "{{.Appname}}", args[0], -1))
if conn != "" {
logger.Infof("Using '%s' as 'driver'", driver)
logger.Infof("Using '%s' as 'conn'", conn)
logger.Infof("Using '%s' as 'tables'", tables)
generateHproseAppcode(string(driver), string(conn), "1", string(tables), path.Join(curpath, args[0]))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
maingoContent := strings.Replace(hproseMainconngo, "{{.Appname}}", packpath, -1)
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1)
maingoContent = strings.Replace(maingoContent, "{{HproseFunctionList}}", strings.Join(hproseAddFunctions, ""), -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)
}
WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(
maingoContent,
"{{.conn}}",
conn.String(),
-1,
),
)
} else {
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "object.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "models", "object.go"), apiModels)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "models", "user.go"), apiModels2)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(hproseMaingo, "{{.Appname}}", packpath, -1))
}
logger.Success("New Hprose application successfully created!")
return 0
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package colors
import (
"fmt"
@ -53,7 +53,7 @@ func NewModeColorWriter(w io.Writer, mode outputMode) io.Writer {
return w
}
func bold(message string) string {
func Bold(message string) string {
return fmt.Sprintf("\x1b[1m%s\x1b[21m", message)
}
@ -102,47 +102,47 @@ func Magenta(message string) string {
return fmt.Sprintf("\x1b[35m%s\x1b[0m", message)
}
// BlackBold returns a black bold string
// BlackBold returns a black Bold string
func BlackBold(message string) string {
return fmt.Sprintf("\x1b[30m%s\x1b[0m", bold(message))
return fmt.Sprintf("\x1b[30m%s\x1b[0m", Bold(message))
}
// WhiteBold returns a white bold string
// WhiteBold returns a white Bold string
func WhiteBold(message string) string {
return fmt.Sprintf("\x1b[37m%s\x1b[0m", bold(message))
return fmt.Sprintf("\x1b[37m%s\x1b[0m", Bold(message))
}
// CyanBold returns a cyan bold string
// CyanBold returns a cyan Bold string
func CyanBold(message string) string {
return fmt.Sprintf("\x1b[36m%s\x1b[0m", bold(message))
return fmt.Sprintf("\x1b[36m%s\x1b[0m", Bold(message))
}
// BlueBold returns a blue bold string
// BlueBold returns a blue Bold string
func BlueBold(message string) string {
return fmt.Sprintf("\x1b[34m%s\x1b[0m", bold(message))
return fmt.Sprintf("\x1b[34m%s\x1b[0m", Bold(message))
}
// RedBold returns a red bold string
// RedBold returns a red Bold string
func RedBold(message string) string {
return fmt.Sprintf("\x1b[31m%s\x1b[0m", bold(message))
return fmt.Sprintf("\x1b[31m%s\x1b[0m", Bold(message))
}
// GreenBold returns a green bold string
// GreenBold returns a green Bold string
func GreenBold(message string) string {
return fmt.Sprintf("\x1b[32m%s\x1b[0m", bold(message))
return fmt.Sprintf("\x1b[32m%s\x1b[0m", Bold(message))
}
// YellowBold returns a yellow bold string
// YellowBold returns a yellow Bold string
func YellowBold(message string) string {
return fmt.Sprintf("\x1b[33m%s\x1b[0m", bold(message))
return fmt.Sprintf("\x1b[33m%s\x1b[0m", Bold(message))
}
// GrayBold returns a gray bold string
// GrayBold returns a gray Bold string
func GrayBold(message string) string {
return fmt.Sprintf("\x1b[37m%s\x1b[0m", bold(message))
return fmt.Sprintf("\x1b[37m%s\x1b[0m", Bold(message))
}
// MagentaBold returns a magenta bold string
// MagentaBold returns a magenta Bold string
func MagentaBold(message string) string {
return fmt.Sprintf("\x1b[35m%s\x1b[0m", bold(message))
return fmt.Sprintf("\x1b[35m%s\x1b[0m", Bold(message))
}

View File

@ -14,7 +14,7 @@
// +build !windows
package main
package colors
import "io"

View File

@ -14,7 +14,7 @@
// +build windows
package main
package colors
import (
"bytes"

View File

@ -11,7 +11,7 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package main
package beeLogger
import (
"errors"
@ -22,6 +22,9 @@ import (
"sync"
"sync/atomic"
"text/template"
"time"
"github.com/beego/bee/logger/colors"
)
var errInvalidLogLevel = errors.New("logger: invalid log level")
@ -59,6 +62,8 @@ type LogRecord struct {
LineNo int
}
var Log = GetBeeLogger(os.Stdout)
var (
logRecordTemplate *template.Template
debugLogRecordTemplate *template.Template
@ -80,11 +85,15 @@ func GetBeeLogger(w io.Writer) *BeeLogger {
"EndLine": EndLine,
}
logRecordTemplate, err = template.New("simpleLogFormat").Funcs(funcs).Parse(simpleLogFormat)
MustCheck(err)
if err != nil {
panic(err)
}
debugLogRecordTemplate, err = template.New("debugLogFormat").Funcs(funcs).Parse(debugLogFormat)
MustCheck(err)
if err != nil {
panic(err)
}
instance = &BeeLogger{output: NewColorWriter(w)}
instance = &BeeLogger{output: colors.NewColorWriter(w)}
})
return instance
}
@ -93,7 +102,17 @@ func GetBeeLogger(w io.Writer) *BeeLogger {
func (l *BeeLogger) SetOutput(w io.Writer) {
l.mu.Lock()
defer l.mu.Unlock()
l.output = NewColorWriter(w)
l.output = colors.NewColorWriter(w)
}
// Now returns the current local time in the specified layout
func Now(layout string) string {
return time.Now().Format(layout)
}
// EndLine returns the a newline escape character
func EndLine() string {
return "\n"
}
func (l *BeeLogger) getLevelTag(level int) string {
@ -122,21 +141,21 @@ func (l *BeeLogger) getLevelTag(level int) string {
func (l *BeeLogger) getColorLevel(level int) string {
switch level {
case levelCritical:
return RedBold(l.getLevelTag(level))
return colors.RedBold(l.getLevelTag(level))
case levelFatal:
return RedBold(l.getLevelTag(level))
return colors.RedBold(l.getLevelTag(level))
case levelInfo:
return BlueBold(l.getLevelTag(level))
return colors.BlueBold(l.getLevelTag(level))
case levelHint:
return CyanBold(l.getLevelTag(level))
return colors.CyanBold(l.getLevelTag(level))
case levelDebug:
return YellowBold(l.getLevelTag(level))
return colors.YellowBold(l.getLevelTag(level))
case levelError:
return RedBold(l.getLevelTag(level))
return colors.RedBold(l.getLevelTag(level))
case levelWarn:
return YellowBold(l.getLevelTag(level))
return colors.YellowBold(l.getLevelTag(level))
case levelSuccess:
return GreenBold(l.getLevelTag(level))
return colors.GreenBold(l.getLevelTag(level))
default:
panic(errInvalidLogLevel)
}
@ -157,15 +176,17 @@ func (l *BeeLogger) mustLog(level int, message string, args ...interface{}) {
}
err := logRecordTemplate.Execute(l.output, record)
MustCheck(err)
if err != nil {
panic(err)
}
}
// mustLogDebug logs a debug message only if debug mode
// is enabled. i.e. DEBUG_ENABLED="1"
func (l *BeeLogger) mustLogDebug(message string, file string, line int, args ...interface{}) {
if !IsDebugEnabled() {
return
}
//if !IsDebugEnabled() {
// return
//}
// Change the output to Stderr
l.SetOutput(os.Stderr)
@ -179,7 +200,9 @@ func (l *BeeLogger) mustLogDebug(message string, file string, line int, args ...
Filename: filepath.Base(file),
}
err := debugLogRecordTemplate.Execute(l.output, record)
MustCheck(err)
if err != nil {
panic(err)
}
}
// Debug outputs a debug log message

59
main.go Normal file
View File

@ -0,0 +1,59 @@
package main
import (
"flag"
"log"
"os"
"strings"
"github.com/beego/bee/cmd"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/generate/swaggergen"
"github.com/beego/bee/utils"
)
func main() {
currentpath, _ := os.Getwd()
flag.Usage = cmd.Usage
flag.Parse()
log.SetFlags(0)
args := flag.Args()
if len(args) < 1 {
cmd.Usage()
}
if args[0] == "help" {
cmd.Help(args[1:])
return
}
for _, c := range commands.AvailableCommands {
if c.Name() == args[0] && c.Run != nil {
c.Flag.Usage = func() { c.Usage() }
if c.CustomFlags {
args = args[1:]
} else {
c.Flag.Parse(args[1:])
args = c.Flag.Args()
}
if c.PreRun != nil {
c.PreRun(c, args)
}
// Check if current directory is inside the GOPATH,
// if so parse the packages inside it.
if strings.Contains(currentpath, utils.GetGOPATHs()[0]+"/src") && cmd.IfGenerateDocs(c.Name(), args) {
swaggergen.ParsePackagesFromDir(currentpath)
}
os.Exit(c.Run(c, args))
return
}
}
utils.PrintErrorAndExit("Unknown subcommand", cmd.ErrorTemplate)
}

View File

@ -1,155 +0,0 @@
// 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.
package main
import (
"archive/zip"
"fmt"
"io"
"net/http"
"os"
"strings"
)
var cmdRundocs = &Command{
UsageLine: "rundocs [-isDownload=true] [-docport=8888]",
Short: "rundocs will run the docs server,default is 8089",
Long: `
-d meaning will download the docs file from github
-p meaning server the Server on which port, default is 8089
`,
}
var (
swaggerVersion = "2"
swaggerlink = "https://github.com/beego/swagger/archive/v" + swaggerVersion + ".zip"
)
type docValue string
func (d *docValue) String() string {
return fmt.Sprint(*d)
}
func (d *docValue) Set(value string) error {
*d = docValue(value)
return nil
}
var isDownload docValue
var docport docValue
func init() {
cmdRundocs.Run = runDocs
cmdRundocs.PreRun = func(cmd *Command, args []string) { ShowShortVersionBanner() }
cmdRundocs.Flag.Var(&isDownload, "isDownload", "weather download the Swagger Docs")
cmdRundocs.Flag.Var(&docport, "docport", "doc server port")
}
func runDocs(cmd *Command, args []string) int {
if isDownload == "true" {
downloadFromURL(swaggerlink, "swagger.zip")
err := unzipAndDelete("swagger.zip")
if err != nil {
logger.Errorf("Error while unzipping 'swagger.zip' file: %s", err)
}
}
if docport == "" {
docport = "8089"
}
if _, err := os.Stat("swagger"); err != nil && os.IsNotExist(err) {
logger.Fatal("No Swagger dist found. Run: bee rundocs -isDownload=true")
}
logger.Infof("Starting the docs server on: http://127.0.0.1:%s", docport)
err := http.ListenAndServe(":"+string(docport), http.FileServer(http.Dir("swagger")))
if err != nil {
logger.Fatalf("%s", err)
}
return 0
}
func downloadFromURL(url, fileName string) {
var down bool
if fd, err := os.Stat(fileName); err != nil && os.IsNotExist(err) {
down = true
} else if fd.Size() == int64(0) {
down = true
} else {
logger.Infof("'%s' already exists", fileName)
return
}
if down {
logger.Infof("Downloading '%s' to '%s'...", url, fileName)
output, err := os.Create(fileName)
if err != nil {
logger.Errorf("Error while creating '%s': %s", fileName, err)
return
}
defer output.Close()
response, err := http.Get(url)
if err != nil {
logger.Errorf("Error while downloading '%s': %s", url, err)
return
}
defer response.Body.Close()
n, err := io.Copy(output, response.Body)
if err != nil {
logger.Errorf("Error while downloading '%s': %s", url, err)
return
}
logger.Successf("%d bytes downloaded!", n)
}
}
func unzipAndDelete(src string) error {
logger.Infof("Unzipping '%s'...", src)
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer r.Close()
rp := strings.NewReplacer("swagger-"+swaggerVersion, "swagger")
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
return err
}
defer rc.Close()
fname := rp.Replace(f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(fname, f.Mode())
} else {
f, err := os.OpenFile(
fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, rc)
if err != nil {
return err
}
}
}
logger.Successf("Done! Deleting '%s'...", src)
return os.RemoveAll(src)
}

102
test.go
View File

@ -1,102 +0,0 @@
// 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.
package main
import (
"os"
"os/exec"
path "path/filepath"
"time"
_ "github.com/smartystreets/goconvey/convey"
)
var cmdTest = &Command{
UsageLine: "test [appname]",
Short: "test the app",
Long: ``,
}
func init() {
cmdTest.Run = testApp
cmdTest.PreRun = func(cmd *Command, args []string) { ShowShortVersionBanner() }
}
func safePathAppend(arr []string, paths ...string) []string {
for _, path := range paths {
if pathExists(path) {
arr = append(arr, path)
}
}
return arr
}
func pathExists(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}
var started = make(chan bool)
func testApp(cmd *Command, args []string) int {
if len(args) != 1 {
logger.Fatalf("Failed to start: %s", "argument 'appname' is missing")
}
currpath, _ := os.Getwd()
logger.Debugf("Current path: %s", __FILE__(), __LINE__(), currpath)
err := loadConfig()
if err != nil {
logger.Fatalf("Failed to load configuration: %s", err)
}
var paths []string
readAppDirectories(currpath, &paths)
NewWatcher(paths, nil, false)
appname = args[0]
for {
select {
case <-started:
runTest()
}
}
}
func runTest() {
logger.Info("Start testing...")
time.Sleep(time.Second * 1)
crupwd, _ := os.Getwd()
testDir := path.Join(crupwd, "tests")
if pathExists(testDir) {
os.Chdir(testDir)
}
var err error
icmd := exec.Command("go", "test")
icmd.Stdout = os.Stdout
icmd.Stderr = os.Stderr
logger.Info("============== Test Begin ===================")
err = icmd.Run()
logger.Info("============== Test End =====================")
if err != nil {
logger.Error("============== Test failed ===================")
logger.Errorf("Cause: %s", err)
return
}
logger.Success("Test Completed")
}

View File

@ -1,28 +0,0 @@
package router
import (
"github.com/astaxie/beego"
)
type Router struct {
beego.Controller
}
func (r *Router) Get() {
}
func (r *Router) Post() {
}
type Controller struct {
}
func (c *Controller) Put() {
}
func (c *Controller) Delete() {
}

14
utils/doc_value.go Normal file
View File

@ -0,0 +1,14 @@
package utils
import "fmt"
type DocValue string
func (d *DocValue) String() string {
return fmt.Sprint(*d)
}
func (d *DocValue) Set(value string) error {
*d = DocValue(value)
return nil
}

14
utils/list_opts.go Normal file
View File

@ -0,0 +1,14 @@
package utils
import "fmt"
type ListOpts []string
func (opts *ListOpts) String() string {
return fmt.Sprint(*opts)
}
func (opts *ListOpts) Set(value string) error {
*opts = append(*opts, value)
return nil
}

15
utils/str_flag.go Normal file
View File

@ -0,0 +1,15 @@
package utils
import "fmt"
// The string flag list, implemented flag.Value interface
type StrFlags []string
func (s *StrFlags) String() string {
return fmt.Sprintf("%s", *s)
}
func (s *StrFlags) Set(value string) error {
*s = append(*s, value)
return nil
}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package utils
import (
"bytes"
@ -26,7 +26,9 @@ import (
"runtime"
"strings"
"text/template"
"time"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
)
// Go is a basic promise implementation: it wraps calls a function in a goroutine
@ -39,18 +41,8 @@ func Go(f func() error) chan error {
return ch
}
// Now returns the current local time in the specified layout
func Now(layout string) string {
return time.Now().Format(layout)
}
// EndLine returns the a newline escape character
func EndLine() string {
return "\n"
}
// IsExist returns whether a file or directory exists.
func isExist(path string) bool {
func IsExist(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}
@ -99,7 +91,7 @@ func IsBeegoProject(thePath string) bool {
}()
if err := <-c; err != nil {
logger.Fatalf("Unable to walk '%s' tree: %s", thePath, err)
beeLogger.Log.Fatalf("Unable to walk '%s' tree: %s", thePath, err)
}
if len(mainFiles) > 0 {
@ -113,7 +105,7 @@ func IsBeegoProject(thePath string) bool {
func SearchGOPATHs(app string) (bool, string, string) {
gps := GetGOPATHs()
if len(gps) == 0 {
logger.Fatal("GOPATH environment variable is not set or empty")
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
// Lookup the application inside the user workspace(s)
@ -127,7 +119,7 @@ func SearchGOPATHs(app string) (bool, string, string) {
currentPath = app
}
if isExist(currentPath) {
if IsExist(currentPath) {
return true, gopath, currentPath
}
}
@ -139,11 +131,11 @@ func SearchGOPATHs(app string) (bool, string, string) {
// confirmations. If the input is not recognized, it will ask again. The function does not return
// until it gets a valid response from the user. Typically, you should use fmt to print out a question
// before calling askForConfirmation. E.g. fmt.Println("WARNING: Are you sure? (yes/no)")
func askForConfirmation() bool {
func AskForConfirmation() bool {
var response string
_, err := fmt.Scanln(&response)
if err != nil {
logger.Fatalf("%s", err)
beeLogger.Log.Fatalf("%s", err)
}
okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
nokayResponses := []string{"n", "N", "no", "No", "NO"}
@ -153,7 +145,7 @@ func askForConfirmation() bool {
return false
} else {
fmt.Println("Please type yes or no and then press enter:")
return askForConfirmation()
return AskForConfirmation()
}
}
@ -167,7 +159,7 @@ func containsString(slice []string, element string) bool {
}
// snake string, XxYy to xx_yy
func snakeString(s string) string {
func SnakeString(s string) string {
data := make([]byte, 0, len(s)*2)
j := false
num := len(s)
@ -184,17 +176,17 @@ func snakeString(s string) string {
return strings.ToLower(string(data[:]))
}
func camelString(s string) string {
func CamelString(s string) string {
data := make([]byte, 0, len(s))
j := false
k := false
num := len(s) - 1
for i := 0; i <= num; i++ {
d := s[i]
if k == false && d >= 'A' && d <= 'Z' {
if !k && d >= 'A' && d <= 'Z' {
k = true
}
if d >= 'a' && d <= 'z' && (j || k == false) {
if d >= 'a' && d <= 'z' && (j || !k) {
d = d - 32
j = false
k = true
@ -210,7 +202,7 @@ func camelString(s string) string {
// camelCase converts a _ delimited string to camel case
// e.g. very_important_person => VeryImportantPerson
func camelCase(in string) string {
func CamelCase(in string) string {
tokens := strings.Split(in, "_")
for i := range tokens {
tokens[i] = strings.Title(strings.Trim(tokens[i], " "))
@ -219,25 +211,13 @@ func camelCase(in string) string {
}
// formatSourceCode formats source files
func formatSourceCode(filename string) {
func FormatSourceCode(filename string) {
cmd := exec.Command("gofmt", "-w", filename)
if err := cmd.Run(); err != nil {
logger.Warnf("Error while running gofmt: %s", err)
beeLogger.Log.Warnf("Error while running gofmt: %s", err)
}
}
// The string flag list, implemented flag.Value interface
type strFlags []string
func (s *strFlags) String() string {
return fmt.Sprintf("%s", *s)
}
func (s *strFlags) Set(value string) error {
*s = append(*s, value)
return nil
}
// CloseFile attempts to close the passed file
// or panics with the actual error
func CloseFile(f *os.File) {
@ -252,11 +232,6 @@ func MustCheck(err error) {
}
}
func exitPrint(con string) {
fmt.Fprintln(os.Stderr, con)
os.Exit(2)
}
// WriteToFile creates a file and writes content to it
func WriteToFile(filename, content string) {
f, err := os.Create(filename)
@ -273,13 +248,13 @@ func IsDebugEnabled() bool {
}
// __FILE__ returns the file name in which the function was invoked
func __FILE__() string {
func FILE() string {
_, file, _, _ := runtime.Caller(1)
return file
}
// __LINE__ returns the line number at which the function was invoked
func __LINE__() int {
func LINE() int {
_, _, line, _ := runtime.Caller(1)
return line
}
@ -288,9 +263,9 @@ func __LINE__() int {
func BeeFuncMap() template.FuncMap {
return template.FuncMap{
"trim": strings.TrimSpace,
"bold": bold,
"headline": MagentaBold,
"foldername": RedBold,
"bold": colors.Bold,
"headline": colors.MagentaBold,
"foldername": colors.RedBold,
"endline": EndLine,
"tmpltostr": TmplToString,
}
@ -307,3 +282,59 @@ func TmplToString(tmpl string, data interface{}) string {
return doc.String()
}
// EndLine returns the a newline escape character
func EndLine() string {
return "\n"
}
func Tmpl(text string, data interface{}) {
output := colors.NewColorWriter(os.Stderr)
t := template.New("Usage").Funcs(BeeFuncMap())
template.Must(t.Parse(text))
err := t.Execute(output, data)
if err != nil {
beeLogger.Log.Error(err.Error())
}
}
func CheckEnv(appname string) (apppath, packpath string, err error) {
gps := GetGOPATHs()
if len(gps) == 0 {
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
currpath, _ := os.Getwd()
currpath = path.Join(currpath, appname)
for _, gpath := range gps {
gsrcpath := path.Join(gpath, "src")
if strings.HasPrefix(currpath, gsrcpath) {
packpath = strings.Replace(currpath[len(gsrcpath)+1:], string(filepath.Separator), "/", -1)
return currpath, packpath, nil
}
}
// In case of multiple paths in the GOPATH, by default
// we use the first path
gopath := gps[0]
beeLogger.Log.Warn("You current workdir is not inside $GOPATH/src.")
beeLogger.Log.Debugf("GOPATH: %s", FILE(), LINE(), gopath)
gosrcpath := path.Join(gopath, "src")
apppath = path.Join(gosrcpath, appname)
if _, e := os.Stat(apppath); !os.IsNotExist(e) {
err = fmt.Errorf("Cannot create application without removing '%s' first.", apppath)
beeLogger.Log.Errorf("Path '%s' already exists", apppath)
return
}
packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(filepath.Separator)), "/")
return
}
func PrintErrorAndExit(message, errorTemplate string) {
Tmpl(fmt.Sprintf(errorTemplate, message), nil)
os.Exit(2)
}