Merge pull request #236 from amrfaissal/color-logger-feature

New tweaks
This commit is contained in:
astaxie 2016-08-02 09:34:48 +08:00 committed by GitHub
commit 4310f5d67f
19 changed files with 813 additions and 207 deletions

View File

@ -548,6 +548,8 @@ func init() {
func createapi(cmd *Command, args []string) int {
ShowShortVersionBanner()
w := NewColorWriter(os.Stdout)
if len(args) < 1 {
ColorLog("[ERRO] Argument [appname] is missing\n")
os.Exit(2)
@ -571,21 +573,21 @@ func createapi(cmd *Command, args []string) int {
ColorLog("[INFO] Creating API...\n")
os.MkdirAll(apppath, 0755)
fmt.Println("\tcreate\t", apppath)
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "conf"))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m")
os.Mkdir(path.Join(apppath, "controllers"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "controllers"))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers"), "\x1b[0m")
os.Mkdir(path.Join(apppath, "docs"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "docs"))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "docs"), "\x1b[0m")
os.Mkdir(path.Join(apppath, "tests"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "tests"))
fmt.Println("\tcreate\t", path.Join(apppath, "conf", "app.conf"))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests"), "\x1b[0m")
fmt.Fprintf(w, "\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(apiconf, "{{.Appname}}", path.Base(args[0]), -1))
if conn != "" {
fmt.Println("\tcreate\t", path.Join(apppath, "main.go"))
fmt.Fprintf(w, "\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" {
@ -607,36 +609,36 @@ func createapi(cmd *Command, args []string) int {
generateAppcode(string(driver), string(conn), "3", string(tables), path.Join(apppath, args[0]))
} else {
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "models"))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m")
os.Mkdir(path.Join(apppath, "routers"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "routers") + string(path.Separator))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers")+string(path.Separator), "\x1b[0m")
fmt.Println("\tcreate\t", path.Join(apppath, "controllers", "object.go"))
fmt.Fprintf(w, "\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"),
strings.Replace(apiControllers, "{{.Appname}}", packpath, -1))
fmt.Println("\tcreate\t", path.Join(apppath, "controllers", "user.go"))
fmt.Fprintf(w, "\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"),
strings.Replace(apiControllers2, "{{.Appname}}", packpath, -1))
fmt.Println("\tcreate\t", path.Join(apppath, "tests", "default_test.go"))
fmt.Fprintf(w, "\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(apiTests, "{{.Appname}}", packpath, -1))
fmt.Println("\tcreate\t", path.Join(apppath, "routers", "router.go"))
fmt.Fprintf(w, "\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(apirouter, "{{.Appname}}", packpath, -1))
fmt.Println("\tcreate\t", path.Join(apppath, "models", "object.go"))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "models", "user.go"))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "docs", "doc.go"))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "docs", "doc.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "docs", "doc.go"), "package docs")
fmt.Println("\tcreate\t", path.Join(apppath, "main.go"))
fmt.Fprintf(w, "\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(apiMaingo, "{{.Appname}}", packpath, -1))
}
@ -645,19 +647,22 @@ func createapi(cmd *Command, args []string) int {
}
func checkEnv(appname string) (apppath, packpath string, err error) {
gopath := os.Getenv("GOPATH")
Debugf("gopath:%s", gopath)
if gopath == "" {
err = fmt.Errorf("you should set GOPATH in the env")
return
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
os.Exit(2)
}
// In case of multiple paths in the GOPATH, by default
// we use the first path
gopath := gps[0]
Debugf("GOPATH: %s", 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)
ColorLog("[ERRO] Path `%s` already exists\n", apppath)
err = fmt.Errorf("Cannot create application without removing '%s' first.", apppath)
ColorLog("[ERRO] Path '%s' already exists\n", apppath)
return
}
packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/")

View File

@ -21,11 +21,12 @@ type vars struct {
BeegoVersion string
}
// Now returns the current local time in the specified layout
func Now(layout string) string {
return time.Now().Format(layout)
}
// Init load the banner and prints it to output
// InitBanner loads the banner and prints it to output
// All errors are ignored, the application will not
// print the banner in case of error.
func InitBanner(out io.Writer, in io.Reader) {
@ -55,7 +56,7 @@ func show(out io.Writer, content string) {
os.Exit(2)
}
t.Execute(out, vars{
err = t.Execute(out, vars{
runtime.Version(),
runtime.GOOS,
runtime.GOARCH,
@ -66,4 +67,7 @@ func show(out io.Writer, content string) {
version,
getBeegoVersion(),
})
if err != nil {
panic(err)
}
}

51
color.go Normal file
View File

@ -0,0 +1,51 @@
// 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 "io"
type outputMode int
// DiscardNonColorEscSeq supports the divided color escape sequence.
// But non-color escape sequence is not output.
// Please use the OutputNonColorEscSeq If you want to output a non-color
// escape sequences such as ncurses. However, it does not support the divided
// color escape sequence.
const (
_ outputMode = iota
DiscardNonColorEscSeq
OutputNonColorEscSeq
)
// NewColorWriter creates and initializes a new ansiColorWriter
// using io.Writer w as its initial contents.
// In the console of Windows, which change the foreground and background
// colors of the text by the escape sequence.
// In the console of other systems, which writes to w all text.
func NewColorWriter(w io.Writer) io.Writer {
return NewModeColorWriter(w, DiscardNonColorEscSeq)
}
// NewModeColorWriter create and initializes a new ansiColorWriter
// by specifying the outputMode.
func NewModeColorWriter(w io.Writer, mode outputMode) io.Writer {
if _, ok := w.(*colorWriter); !ok {
return &colorWriter{
w: w,
mode: mode,
}
}
return w
}

28
colorwriter.go Normal file
View File

@ -0,0 +1,28 @@
// 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.
// +build !windows
package main
import "io"
type colorWriter struct {
w io.Writer
mode outputMode
}
func (cw *colorWriter) Write(p []byte) (int, error) {
return cw.w.Write(p)
}

427
colorwriter_windows.go Normal file
View File

@ -0,0 +1,427 @@
// 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.
// +build windows
package main
import (
"bytes"
"io"
"strings"
"syscall"
"unsafe"
)
type csiState int
const (
outsideCsiCode csiState = iota
firstCsiCode
secondCsiCode
)
type parseResult int
const (
noConsole parseResult = iota
changedColor
unknown
)
type colorWriter struct {
w io.Writer
mode outputMode
state csiState
paramStartBuf bytes.Buffer
paramBuf bytes.Buffer
}
const (
firstCsiChar byte = '\x1b'
secondeCsiChar byte = '['
separatorChar byte = ';'
sgrCode byte = 'm'
)
const (
foregroundBlue = uint16(0x0001)
foregroundGreen = uint16(0x0002)
foregroundRed = uint16(0x0004)
foregroundIntensity = uint16(0x0008)
backgroundBlue = uint16(0x0010)
backgroundGreen = uint16(0x0020)
backgroundRed = uint16(0x0040)
backgroundIntensity = uint16(0x0080)
underscore = uint16(0x8000)
foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity
backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity
)
const (
ansiReset = "0"
ansiIntensityOn = "1"
ansiIntensityOff = "21"
ansiUnderlineOn = "4"
ansiUnderlineOff = "24"
ansiBlinkOn = "5"
ansiBlinkOff = "25"
ansiForegroundBlack = "30"
ansiForegroundRed = "31"
ansiForegroundGreen = "32"
ansiForegroundYellow = "33"
ansiForegroundBlue = "34"
ansiForegroundMagenta = "35"
ansiForegroundCyan = "36"
ansiForegroundWhite = "37"
ansiForegroundDefault = "39"
ansiBackgroundBlack = "40"
ansiBackgroundRed = "41"
ansiBackgroundGreen = "42"
ansiBackgroundYellow = "43"
ansiBackgroundBlue = "44"
ansiBackgroundMagenta = "45"
ansiBackgroundCyan = "46"
ansiBackgroundWhite = "47"
ansiBackgroundDefault = "49"
ansiLightForegroundGray = "90"
ansiLightForegroundRed = "91"
ansiLightForegroundGreen = "92"
ansiLightForegroundYellow = "93"
ansiLightForegroundBlue = "94"
ansiLightForegroundMagenta = "95"
ansiLightForegroundCyan = "96"
ansiLightForegroundWhite = "97"
ansiLightBackgroundGray = "100"
ansiLightBackgroundRed = "101"
ansiLightBackgroundGreen = "102"
ansiLightBackgroundYellow = "103"
ansiLightBackgroundBlue = "104"
ansiLightBackgroundMagenta = "105"
ansiLightBackgroundCyan = "106"
ansiLightBackgroundWhite = "107"
)
type drawType int
const (
foreground drawType = iota
background
)
type winColor struct {
code uint16
drawType drawType
}
var colorMap = map[string]winColor{
ansiForegroundBlack: {0, foreground},
ansiForegroundRed: {foregroundRed, foreground},
ansiForegroundGreen: {foregroundGreen, foreground},
ansiForegroundYellow: {foregroundRed | foregroundGreen, foreground},
ansiForegroundBlue: {foregroundBlue, foreground},
ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground},
ansiForegroundCyan: {foregroundGreen | foregroundBlue, foreground},
ansiForegroundWhite: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
ansiBackgroundBlack: {0, background},
ansiBackgroundRed: {backgroundRed, background},
ansiBackgroundGreen: {backgroundGreen, background},
ansiBackgroundYellow: {backgroundRed | backgroundGreen, background},
ansiBackgroundBlue: {backgroundBlue, background},
ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background},
ansiBackgroundCyan: {backgroundGreen | backgroundBlue, background},
ansiBackgroundWhite: {backgroundRed | backgroundGreen | backgroundBlue, background},
ansiBackgroundDefault: {0, background},
ansiLightForegroundGray: {foregroundIntensity, foreground},
ansiLightForegroundRed: {foregroundIntensity | foregroundRed, foreground},
ansiLightForegroundGreen: {foregroundIntensity | foregroundGreen, foreground},
ansiLightForegroundYellow: {foregroundIntensity | foregroundRed | foregroundGreen, foreground},
ansiLightForegroundBlue: {foregroundIntensity | foregroundBlue, foreground},
ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground},
ansiLightForegroundCyan: {foregroundIntensity | foregroundGreen | foregroundBlue, foreground},
ansiLightForegroundWhite: {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground},
ansiLightBackgroundGray: {backgroundIntensity, background},
ansiLightBackgroundRed: {backgroundIntensity | backgroundRed, background},
ansiLightBackgroundGreen: {backgroundIntensity | backgroundGreen, background},
ansiLightBackgroundYellow: {backgroundIntensity | backgroundRed | backgroundGreen, background},
ansiLightBackgroundBlue: {backgroundIntensity | backgroundBlue, background},
ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background},
ansiLightBackgroundCyan: {backgroundIntensity | backgroundGreen | backgroundBlue, background},
ansiLightBackgroundWhite: {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background},
}
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
defaultAttr *textAttributes
)
func init() {
screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
if screenInfo != nil {
colorMap[ansiForegroundDefault] = winColor{
screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue),
foreground,
}
colorMap[ansiBackgroundDefault] = winColor{
screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue),
background,
}
defaultAttr = convertTextAttr(screenInfo.WAttributes)
}
}
type coord struct {
X, Y int16
}
type smallRect struct {
Left, Top, Right, Bottom int16
}
type consoleScreenBufferInfo struct {
DwSize coord
DwCursorPosition coord
WAttributes uint16
SrWindow smallRect
DwMaximumWindowSize coord
}
func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
var csbi consoleScreenBufferInfo
ret, _, _ := procGetConsoleScreenBufferInfo.Call(
hConsoleOutput,
uintptr(unsafe.Pointer(&csbi)))
if ret == 0 {
return nil
}
return &csbi
}
func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
ret, _, _ := procSetConsoleTextAttribute.Call(
hConsoleOutput,
uintptr(wAttributes))
return ret != 0
}
type textAttributes struct {
foregroundColor uint16
backgroundColor uint16
foregroundIntensity uint16
backgroundIntensity uint16
underscore uint16
otherAttributes uint16
}
func convertTextAttr(winAttr uint16) *textAttributes {
fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue)
bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue)
fgIntensity := winAttr & foregroundIntensity
bgIntensity := winAttr & backgroundIntensity
underline := winAttr & underscore
otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore)
return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes}
}
func convertWinAttr(textAttr *textAttributes) uint16 {
var winAttr uint16
winAttr |= textAttr.foregroundColor
winAttr |= textAttr.backgroundColor
winAttr |= textAttr.foregroundIntensity
winAttr |= textAttr.backgroundIntensity
winAttr |= textAttr.underscore
winAttr |= textAttr.otherAttributes
return winAttr
}
func changeColor(param []byte) parseResult {
screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
if screenInfo == nil {
return noConsole
}
winAttr := convertTextAttr(screenInfo.WAttributes)
strParam := string(param)
if len(strParam) <= 0 {
strParam = "0"
}
csiParam := strings.Split(strParam, string(separatorChar))
for _, p := range csiParam {
c, ok := colorMap[p]
switch {
case !ok:
switch p {
case ansiReset:
winAttr.foregroundColor = defaultAttr.foregroundColor
winAttr.backgroundColor = defaultAttr.backgroundColor
winAttr.foregroundIntensity = defaultAttr.foregroundIntensity
winAttr.backgroundIntensity = defaultAttr.backgroundIntensity
winAttr.underscore = 0
winAttr.otherAttributes = 0
case ansiIntensityOn:
winAttr.foregroundIntensity = foregroundIntensity
case ansiIntensityOff:
winAttr.foregroundIntensity = 0
case ansiUnderlineOn:
winAttr.underscore = underscore
case ansiUnderlineOff:
winAttr.underscore = 0
case ansiBlinkOn:
winAttr.backgroundIntensity = backgroundIntensity
case ansiBlinkOff:
winAttr.backgroundIntensity = 0
default:
// unknown code
}
case c.drawType == foreground:
winAttr.foregroundColor = c.code
case c.drawType == background:
winAttr.backgroundColor = c.code
}
}
winTextAttribute := convertWinAttr(winAttr)
setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute)
return changedColor
}
func parseEscapeSequence(command byte, param []byte) parseResult {
if defaultAttr == nil {
return noConsole
}
switch command {
case sgrCode:
return changeColor(param)
default:
return unknown
}
}
func (cw *colorWriter) flushBuffer() (int, error) {
return cw.flushTo(cw.w)
}
func (cw *colorWriter) resetBuffer() (int, error) {
return cw.flushTo(nil)
}
func (cw *colorWriter) flushTo(w io.Writer) (int, error) {
var n1, n2 int
var err error
startBytes := cw.paramStartBuf.Bytes()
cw.paramStartBuf.Reset()
if w != nil {
n1, err = cw.w.Write(startBytes)
if err != nil {
return n1, err
}
} else {
n1 = len(startBytes)
}
paramBytes := cw.paramBuf.Bytes()
cw.paramBuf.Reset()
if w != nil {
n2, err = cw.w.Write(paramBytes)
if err != nil {
return n1 + n2, err
}
} else {
n2 = len(paramBytes)
}
return n1 + n2, nil
}
func isParameterChar(b byte) bool {
return ('0' <= b && b <= '9') || b == separatorChar
}
func (cw *colorWriter) Write(p []byte) (int, error) {
r, nw, first, last := 0, 0, 0, 0
if cw.mode != DiscardNonColorEscSeq {
cw.state = outsideCsiCode
cw.resetBuffer()
}
var err error
for i, ch := range p {
switch cw.state {
case outsideCsiCode:
if ch == firstCsiChar {
cw.paramStartBuf.WriteByte(ch)
cw.state = firstCsiCode
}
case firstCsiCode:
switch ch {
case firstCsiChar:
cw.paramStartBuf.WriteByte(ch)
break
case secondeCsiChar:
cw.paramStartBuf.WriteByte(ch)
cw.state = secondCsiCode
last = i - 1
default:
cw.resetBuffer()
cw.state = outsideCsiCode
}
case secondCsiCode:
if isParameterChar(ch) {
cw.paramBuf.WriteByte(ch)
} else {
nw, err = cw.w.Write(p[first:last])
r += nw
if err != nil {
return r, err
}
first = i + 1
result := parseEscapeSequence(ch, cw.paramBuf.Bytes())
if result == noConsole || (cw.mode == OutputNonColorEscSeq && result == unknown) {
cw.paramBuf.WriteByte(ch)
nw, err := cw.flushBuffer()
if err != nil {
return r, err
}
r += nw
} else {
n, _ := cw.resetBuffer()
// Add one more to the size of the buffer for the last ch
r += n + 1
}
cw.state = outsideCsiCode
}
default:
cw.state = outsideCsiCode
}
}
if cw.mode != DiscardNonColorEscSeq || cw.state == outsideCsiCode {
nw, err = cw.w.Write(p[first:len(p)])
r += nw
}
return r, err
}

32
g.go
View File

@ -35,7 +35,7 @@ bee generate model [modelname] [-fields=""]
-fields: a list of table fields. Format: field:type, ...
bee generate controller [controllerfile]
generate RESTFul controllers
generate RESTful controllers
bee generate view [viewpath]
generate CRUD view in viewpath
@ -43,7 +43,7 @@ bee generate view [viewpath]
bee generate migration [migrationfile] [-fields=""]
generate migration file for making database schema update
-fields: a list of table fields. Format: field:type, ...
bee generate docs
generate swagger doc file
@ -79,19 +79,19 @@ func init() {
func generateCode(cmd *Command, args []string) int {
ShowShortVersionBanner()
curpath, _ := os.Getwd()
currpath, _ := os.Getwd()
if len(args) < 1 {
ColorLog("[ERRO] command is missing\n")
os.Exit(2)
}
gopath := os.Getenv("GOPATH")
Debugf("gopath:%s", gopath)
if gopath == "" {
ColorLog("[ERRO] $GOPATH not found\n")
ColorLog("[HINT] Set $GOPATH in your environment vairables\n")
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
os.Exit(2)
}
gopath := gps[0]
Debugf("GOPATH: %s", gopath)
gcmd := args[0]
switch gcmd {
@ -124,9 +124,9 @@ func generateCode(cmd *Command, args []string) int {
os.Exit(2)
}
sname := args[1]
generateScaffold(sname, fields.String(), curpath, driver.String(), conn.String())
generateScaffold(sname, fields.String(), currpath, driver.String(), conn.String())
case "docs":
generateDocs(curpath)
generateDocs(currpath)
case "appcode":
// load config
err := loadConfig()
@ -157,7 +157,7 @@ func generateCode(cmd *Command, args []string) int {
ColorLog("[INFO] Using '%s' as 'conn'\n", conn)
ColorLog("[INFO] Using '%s' as 'tables'\n", tables)
ColorLog("[INFO] Using '%s' as 'level'\n", level)
generateAppcode(driver.String(), conn.String(), level.String(), tables.String(), curpath)
generateAppcode(driver.String(), conn.String(), level.String(), tables.String(), currpath)
case "migration":
if len(args) < 2 {
ColorLog("[ERRO] Wrong number of arguments\n")
@ -176,11 +176,11 @@ func generateCode(cmd *Command, args []string) int {
downsql = strings.Replace(downsql, "`", "", -1)
}
}
generateMigration(mname, upsql, downsql, curpath)
generateMigration(mname, upsql, downsql, currpath)
case "controller":
if len(args) == 2 {
cname := args[1]
generateController(cname, curpath)
generateController(cname, currpath)
} else {
ColorLog("[ERRO] Wrong number of arguments\n")
ColorLog("[HINT] Usage: bee generate controller [controllername]\n")
@ -199,18 +199,18 @@ func generateCode(cmd *Command, args []string) int {
os.Exit(2)
}
sname := args[1]
generateModel(sname, fields.String(), curpath)
generateModel(sname, fields.String(), currpath)
case "view":
if len(args) == 2 {
cname := args[1]
generateView(cname, curpath)
generateView(cname, currpath)
} else {
ColorLog("[ERRO] Wrong number of arguments\n")
ColorLog("[HINT] Usage: bee generate view [viewpath]\n")
os.Exit(2)
}
default:
ColorLog("[ERRO] command is missing\n")
ColorLog("[ERRO] Command is missing\n")
}
ColorLog("[SUCC] %s successfully generated!\n", strings.Title(gcmd))
return 0

View File

@ -499,7 +499,7 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
}
}
// getGoDataType maps an SQL data type to Golang data type
// GetGoDataType maps an SQL data type to Golang data type
func (*MysqlDB) GetGoDataType(sqlType string) (goType string) {
var typeMapping = map[string]string{}
typeMapping = typeMappingMysql
@ -688,6 +688,8 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map
table.Columns = append(table.Columns, col)
}
}
// GetGoDataType returns the Go type from the mapped Postgres type
func (*PostgresDB) GetGoDataType(sqlType string) (goType string) {
if v, ok := typeMappingPostgres[sqlType]; ok {
return v
@ -730,6 +732,8 @@ func writeSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath
// writeModelFiles generates model files
func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bool) {
w := NewColorWriter(os.Stdout)
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
if selectedTables != nil {
@ -742,7 +746,7 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath)
ColorLog("[WARN] '%v' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
@ -750,7 +754,7 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo
continue
}
} else {
ColorLog("[WARN] skip create file\n")
ColorLog("[WARN] Skipped create file '%s'\n", fpath)
continue
}
} else {
@ -782,14 +786,16 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo
ColorLog("[ERRO] Could not write model file to %s\n", fpath)
os.Exit(2)
}
f.Close()
ColorLog("[INFO] model => %s\n", fpath)
CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
}
}
// writeControllerFiles generates controller files
func writeControllerFiles(tables []*Table, cPath string, selectedTables map[string]bool, pkgPath string) {
w := NewColorWriter(os.Stdout)
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
if selectedTables != nil {
@ -805,7 +811,7 @@ func writeControllerFiles(tables []*Table, cPath string, selectedTables map[stri
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath)
ColorLog("[WARN] '%v' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
@ -813,7 +819,7 @@ func writeControllerFiles(tables []*Table, cPath string, selectedTables map[stri
continue
}
} else {
ColorLog("[WARN] skip create file\n")
ColorLog("[WARN] Skipped create file '%s'\n", fpath)
continue
}
} else {
@ -829,14 +835,16 @@ func writeControllerFiles(tables []*Table, cPath string, selectedTables map[stri
ColorLog("[ERRO] Could not write controller file to %s\n", fpath)
os.Exit(2)
}
f.Close()
ColorLog("[INFO] controller => %s\n", fpath)
CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
}
}
// writeRouterFile generates router file
func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bool, pkgPath string) {
w := NewColorWriter(os.Stdout)
var nameSpaces []string
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
@ -848,7 +856,7 @@ func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bo
if tb.Pk == "" {
continue
}
// add name spaces
// add namespaces
nameSpace := strings.Replace(NamespaceTPL, "{{nameSpace}}", tb.Name, -1)
nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", camelCase(tb.Name), -1)
nameSpaces = append(nameSpaces, nameSpace)
@ -860,7 +868,7 @@ func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bo
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath)
ColorLog("[WARN] '%v' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
@ -868,7 +876,7 @@ func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bo
return
}
} else {
ColorLog("[WARN] skip create file\n")
ColorLog("[WARN] Skipped create file '%s'\n", fpath)
return
}
} else {
@ -879,11 +887,11 @@ func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bo
}
}
if _, err := f.WriteString(routerStr); err != nil {
ColorLog("[ERRO] Could not write router file to %s\n", fpath)
ColorLog("[ERRO] Could not write router file to '%s'\n", fpath)
os.Exit(2)
}
f.Close()
ColorLog("[INFO] router => %s\n", fpath)
CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
}
@ -966,7 +974,7 @@ func getPackagePath(curpath string) (packpath string) {
gopath := os.Getenv("GOPATH")
Debugf("gopath:%s", gopath)
if gopath == "" {
ColorLog("[ERRO] you should set GOPATH in the env")
ColorLog("[ERRO] You should set GOPATH in the env")
os.Exit(2)
}

View File

@ -15,53 +15,62 @@
package main
import (
"fmt"
"os"
"path"
"strings"
"fmt"
)
// article
// cms/article
//
func generateController(cname, crupath string) {
func generateController(cname, currpath string) {
w := NewColorWriter(os.Stdout)
p, f := path.Split(cname)
controllerName := strings.Title(f)
packageName := "controllers"
if p != "" {
i := strings.LastIndex(p[:len(p)-1], "/")
packageName = p[i+1 : len(p)-1]
}
ColorLog("[INFO] Using '%s' as controller name\n", controllerName)
ColorLog("[INFO] Using '%s' as package name\n", packageName)
fp := path.Join(crupath, "controllers", p)
fp := path.Join(currpath, "controllers", p)
if _, err := os.Stat(fp); os.IsNotExist(err) {
// create controller directory
// Create the controller's directory
if err := os.MkdirAll(fp, 0777); err != nil {
ColorLog("[ERRO] Could not create controllers directory: %s\n", err)
os.Exit(2)
}
}
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 f.Close()
modelPath := path.Join(crupath, "models", strings.ToLower(controllerName)+".go")
defer CloseFile(f)
modelPath := path.Join(currpath, "models", strings.ToLower(controllerName)+".go")
var content string
if _, err := os.Stat(modelPath); err == nil {
ColorLog("[INFO] Using matching model '%s'\n", controllerName)
content = strings.Replace(controllerModelTpl, "{{packageName}}", packageName, -1)
pkgPath := getPackagePath(crupath)
pkgPath := getPackagePath(currpath)
content = strings.Replace(content, "{{pkgPath}}", pkgPath, -1)
} else {
content = strings.Replace(controllerTpl, "{{packageName}}", packageName, -1)
}
content = strings.Replace(content, "{{controllerName}}", controllerName, -1)
f.WriteString(content)
// gofmt generated source code
// Run 'gofmt' on the generated source code
formatSourceCode(fpath)
fmt.Println("\tcreate\t", fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
} else {
// error creating file
ColorLog("[ERRO] Could not create controller file: %s\n", err)
os.Exit(2)
}

View File

@ -19,6 +19,7 @@ package main
import (
"database/sql"
"fmt"
"os"
"path"
"strings"
@ -98,6 +99,8 @@ func writeHproseSourceFiles(pkgPath string, tables []*Table, mode byte, paths *M
// writeHproseModelFiles generates model files
func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[string]bool) {
w := NewColorWriter(os.Stdout)
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
if selectedTables != nil {
@ -110,7 +113,7 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath)
ColorLog("[WARN] '%v' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
@ -118,7 +121,7 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str
continue
}
} else {
ColorLog("[WARN] skip create file\n")
ColorLog("[WARN] Skipped create file '%s'\n", fpath)
continue
}
} else {
@ -147,11 +150,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 {
ColorLog("[ERRO] Could not write model file to %s\n", fpath)
ColorLog("[ERRO] Could not write model file to '%s'\n", fpath)
os.Exit(2)
}
f.Close()
ColorLog("[INFO] model => %s\n", fpath)
CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
}
}

View File

@ -23,7 +23,7 @@ import (
)
const (
MPath = "migrations"
MPath = "migrations"
MDateFormat = "20060102_150405"
)
@ -31,6 +31,8 @@ const (
// 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)
migrationFilePath := path.Join(curpath, "database", MPath)
if _, err := os.Stat(migrationFilePath); os.IsNotExist(err) {
// create migrations directory
@ -43,17 +45,16 @@ func generateMigration(mname, upsql, downsql, curpath string) {
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 f.Close()
defer CloseFile(f)
content := strings.Replace(MigrationTPL, "{{StructName}}", 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)
// gofmt generated source code
// Run 'gofmt' on the generated source code
formatSourceCode(fpath)
fmt.Println("\tcreate\t", fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
} else {
// error creating file
ColorLog("[ERRO] Could not create migration file: %s\n", err)
os.Exit(2)
}

View File

@ -1,3 +1,17 @@
// 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 (
@ -8,7 +22,9 @@ import (
"strings"
)
func generateModel(mname, fields, crupath string) {
func generateModel(mname, fields, currpath string) {
w := NewColorWriter(os.Stdout)
p, f := path.Split(mname)
modelName := strings.Title(f)
packageName := "models"
@ -16,24 +32,28 @@ func generateModel(mname, fields, crupath string) {
i := strings.LastIndex(p[:len(p)-1], "/")
packageName = p[i+1 : len(p)-1]
}
modelStruct, hastime, err := getStruct(modelName, fields)
if err != nil {
ColorLog("[ERRO] Could not genrate models struct: %s\n", err)
ColorLog("[ERRO] Could not generate the model struct: %s\n", err)
os.Exit(2)
}
ColorLog("[INFO] Using '%s' as model name\n", modelName)
ColorLog("[INFO] Using '%s' as package name\n", packageName)
fp := path.Join(crupath, "models", p)
fp := path.Join(currpath, "models", p)
if _, err := os.Stat(fp); os.IsNotExist(err) {
// create controller directory
// Create the model's directory
if err := os.MkdirAll(fp, 0777); err != nil {
ColorLog("[ERRO] Could not create models directory: %s\n", err)
ColorLog("[ERRO] Could not create the model directory: %s\n", err)
os.Exit(2)
}
}
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 f.Close()
defer CloseFile(f)
content := strings.Replace(modelTpl, "{{packageName}}", packageName, -1)
content = strings.Replace(content, "{{modelName}}", modelName, -1)
content = strings.Replace(content, "{{modelStruct}}", modelStruct, -1)
@ -43,11 +63,10 @@ func generateModel(mname, fields, crupath string) {
content = strings.Replace(content, "{{timePkg}}", "", -1)
}
f.WriteString(content)
// gofmt generated source code
// Run 'gofmt' on the generated source code
formatSourceCode(fpath)
fmt.Println("\tcreate\t", fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
} else {
// error creating file
ColorLog("[ERRO] Could not create model file: %s\n", err)
os.Exit(2)
}
@ -55,23 +74,27 @@ func generateModel(mname, fields, crupath string) {
func getStruct(structname, fields string) (string, bool, error) {
if fields == "" {
return "", false, errors.New("fields can't empty")
return "", false, errors.New("fields cannot be empty")
}
hastime := false
structStr := "type " + structname + " struct{\n"
fds := strings.Split(fields, ",")
for i, v := range fds {
kv := strings.SplitN(v, ":", 2)
if len(kv) != 2 {
return "", false, errors.New("the filds format is wrong. should key:type,key:type " + v)
return "", false, errors.New("the fields format is wrong. Should be key:type,key:type " + v)
}
typ, tag, hastimeinner := getType(kv[1])
if typ == "" {
return "", false, errors.New("the filds format is wrong. should key:type,key:type " + v)
return "", false, errors.New("the fields format is wrong. Should be key:type,key:type " + v)
}
if i == 0 && strings.ToLower(kv[0]) != "id" {
structStr = structStr + "Id int64 `orm:\"auto\"`\n"
}
if hastimeinner {
hastime = true
}

View File

@ -5,25 +5,28 @@ import (
"strings"
)
func generateScaffold(sname, fields, crupath, driver, conn string) {
// generate model
ColorLog("[INFO] Do you want to create a %v model? [yes|no]] ", sname)
func generateScaffold(sname, fields, currpath, driver, conn string) {
ColorLog("[INFO] Do you want to create a '%v' model? [Yes|No] ", sname)
// Generate the model
if askForConfirmation() {
generateModel(sname, fields, crupath)
generateModel(sname, fields, currpath)
}
// generate controller
ColorLog("[INFO] Do you want to create a %v controller? [yes|no]] ", sname)
// Generate the controller
ColorLog("[INFO] Do you want to create a '%v' controller? [Yes|No] ", sname)
if askForConfirmation() {
generateController(sname, crupath)
generateController(sname, currpath)
}
// generate view
ColorLog("[INFO] Do you want to create views for this %v resource? [yes|no]] ", sname)
// Generate the views
ColorLog("[INFO] Do you want to create views for this '%v' resource? [Yes|No] ", sname)
if askForConfirmation() {
generateView(sname, crupath)
generateView(sname, currpath)
}
// generate migration
ColorLog("[INFO] Do you want to create a %v migration and schema for this resource? [yes|no]] ", sname)
// Generate a migration
ColorLog("[INFO] Do you want to create a '%v' migration and schema for this resource? [Yes|No] ", sname)
if askForConfirmation() {
upsql := ""
downsql := ""
@ -34,12 +37,13 @@ func generateScaffold(sname, fields, crupath, driver, conn string) {
downsql = strings.Replace(downsql, "`", "", -1)
}
}
generateMigration(sname, upsql, downsql, crupath)
generateMigration(sname, upsql, downsql, currpath)
}
// run migration
ColorLog("[INFO] Do you want to migrate the database? [yes|no]] ")
// Run the migration
ColorLog("[INFO] Do you want to migrate the database? [Yes|No] ")
if askForConfirmation() {
migrateUpdate(crupath, driver, conn)
migrateUpdate(currpath, driver, conn)
}
ColorLog("[INFO] All done! Don't forget to add beego.Router(\"/%v\" ,&controllers.%vController{}) to routers/route.go\n", sname, strings.Title(sname))
}

View File

@ -1,49 +1,74 @@
// 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"
"fmt"
)
// recipe
// admin/recipe
func generateView(vpath, crupath string) {
func generateView(viewpath, currpath string) {
w := NewColorWriter(os.Stdout)
ColorLog("[INFO] Generating view...\n")
absvpath := path.Join(crupath, "views", vpath)
os.MkdirAll(absvpath, os.ModePerm)
cfile := path.Join(absvpath, "index.tpl")
absViewPath := path.Join(currpath, "views", viewpath)
err := os.MkdirAll(absViewPath, os.ModePerm)
if err != nil {
ColorLog("[ERRO] Could not create '%s' view: %s\n", viewpath, err)
os.Exit(2)
}
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 f.Close()
defer CloseFile(f)
f.WriteString(cfile)
fmt.Println("\tcreate\t", cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
}
cfile = path.Join(absvpath, "show.tpl")
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 f.Close()
defer CloseFile(f)
f.WriteString(cfile)
fmt.Println("\tcreate\t", cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
}
cfile = path.Join(absvpath, "create.tpl")
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 f.Close()
defer CloseFile(f)
f.WriteString(cfile)
fmt.Println("\tcreate\t", cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
}
cfile = path.Join(absvpath, "edit.tpl")
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 f.Close()
defer CloseFile(f)
f.WriteString(cfile)
fmt.Println("\tcreate\t", cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)

View File

@ -28,7 +28,7 @@ var cmdHproseapp = &Command{
// CustomFlags: true,
UsageLine: "hprose [appname]",
Short: "create an rpc application use hprose base on beego framework",
Long: `
Long: `
create an rpc application use hprose base on beego framework
bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test]
@ -37,7 +37,7 @@ bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:330
-conn: the connection string used by the driver, the default is ''
e.g. for mysql: root:@tcp(127.0.0.1:3306)/test
e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
if conn is empty will create a example rpc application. otherwise generate rpc application use hprose based on an existing database.
In the current path, will create a folder named [appname]
@ -257,6 +257,8 @@ func init() {
func createhprose(cmd *Command, args []string) int {
ShowShortVersionBanner()
w := NewColorWriter(os.Stdout)
curpath, _ := os.Getwd()
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
@ -275,10 +277,10 @@ func createhprose(cmd *Command, args []string) int {
ColorLog("[INFO] Creating Hprose application...\n")
os.MkdirAll(apppath, 0755)
fmt.Println("\tcreate\t", apppath)
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "conf"))
fmt.Println("\tcreate\t", path.Join(apppath, "conf", "app.conf"))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m")
fmt.Fprintf(w, "\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))
@ -287,7 +289,7 @@ func createhprose(cmd *Command, args []string) int {
ColorLog("[INFO] Using '%s' as 'conn'\n", conn)
ColorLog("[INFO] Using '%s' as 'tables'\n", tables)
generateHproseAppcode(string(driver), string(conn), "1", string(tables), path.Join(curpath, args[0]))
fmt.Println("\tcreate\t", path.Join(apppath, "main.go"))
fmt.Fprintf(w, "\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)
@ -306,15 +308,15 @@ func createhprose(cmd *Command, args []string) int {
)
} else {
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "models"))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m")
fmt.Println("\tcreate\t", path.Join(apppath, "models", "object.go"))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "models", "user.go"))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "main.go"))
fmt.Fprintf(w, "\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))
}

View File

@ -64,15 +64,16 @@ func init() {
func runMigration(cmd *Command, args []string) int {
ShowShortVersionBanner()
crupath, _ := os.Getwd()
currpath, _ := os.Getwd()
gopath := os.Getenv("GOPATH")
Debugf("gopath:%s", gopath)
if gopath == "" {
ColorLog("[ERRO] $GOPATH not found\n")
ColorLog("[HINT] Set $GOPATH in your environment vairables\n")
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
os.Exit(2)
}
gopath := gps[0]
Debugf("GOPATH: %s", gopath)
// load config
err := loadConfig()
if err != nil {
@ -100,19 +101,19 @@ func runMigration(cmd *Command, args []string) int {
if len(args) == 0 {
// run all outstanding migrations
ColorLog("[INFO] Running all outstanding migrations\n")
migrateUpdate(crupath, driverStr, connStr)
migrateUpdate(currpath, driverStr, connStr)
} else {
mcmd := args[0]
switch mcmd {
case "rollback":
ColorLog("[INFO] Rolling back the last migration operation\n")
migrateRollback(crupath, driverStr, connStr)
migrateRollback(currpath, driverStr, connStr)
case "reset":
ColorLog("[INFO] Reseting all migrations\n")
migrateReset(crupath, driverStr, connStr)
migrateReset(currpath, driverStr, connStr)
case "refresh":
ColorLog("[INFO] Refreshing all migrations\n")
migrateRefresh(crupath, driverStr, connStr)
migrateRefresh(currpath, driverStr, connStr)
default:
ColorLog("[ERRO] Command is missing\n")
os.Exit(2)
@ -123,28 +124,28 @@ func runMigration(cmd *Command, args []string) int {
}
// migrateUpdate does the schema update
func migrateUpdate(crupath, driver, connStr string) {
migrate("upgrade", crupath, driver, connStr)
func migrateUpdate(currpath, driver, connStr string) {
migrate("upgrade", currpath, driver, connStr)
}
// migrateRollback rolls back the latest migration
func migrateRollback(crupath, driver, connStr string) {
migrate("rollback", crupath, driver, connStr)
func migrateRollback(currpath, driver, connStr string) {
migrate("rollback", currpath, driver, connStr)
}
// migrateReset rolls back all migrations
func migrateReset(crupath, driver, connStr string) {
migrate("reset", crupath, driver, connStr)
func migrateReset(currpath, driver, connStr string) {
migrate("reset", currpath, driver, connStr)
}
// migrationRefresh rolls back all migrations and start over again
func migrateRefresh(crupath, driver, connStr string) {
migrate("refresh", crupath, driver, connStr)
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, crupath, driver, connStr string) {
dir := path.Join(crupath, "database", "migrations")
func migrate(goal, currpath, driver, connStr string) {
dir := path.Join(currpath, "database", "migrations")
binary := "m"
source := binary + ".go"
// connect to database
@ -299,7 +300,7 @@ func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime in
ColorLog("[ERRO] Could not write to file: %s\n", err)
os.Exit(2)
}
f.Close()
CloseFile(f)
}
}

53
new.go
View File

@ -57,25 +57,29 @@ func init() {
func createApp(cmd *Command, args []string) int {
ShowShortVersionBanner()
w := NewColorWriter(os.Stdout)
if len(args) != 1 {
ColorLog("[ERRO] Argument [appname] is missing\n")
os.Exit(2)
}
gopath := os.Getenv("GOPATH")
Debugf("gopath:%s", gopath)
if gopath == "" {
ColorLog("[ERRO] $GOPATH not found\n")
ColorLog("[HINT] Set $GOPATH in your environment variables\n")
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
os.Exit(2)
}
// In case of multiple paths in the GOPATH, by default
// we use the first path
gopath := gps[0]
Debugf("GOPATH: %s", gopath)
gosrcpath := path.Join(gopath, "src") // User's workspace
apppath := path.Join(gosrcpath, args[0])
if isExist(apppath) {
ColorLog("[ERRO] Path (%s) already exists\n", apppath)
ColorLog("[WARN] Do you want to overwrite it? [yes|no]]")
ColorLog("[WARN] Do you want to overwrite it? [Yes|No] ")
if !askForConfirmation() {
os.Exit(2)
}
@ -84,43 +88,43 @@ func createApp(cmd *Command, args []string) int {
ColorLog("[INFO] Creating application...\n")
os.MkdirAll(apppath, 0755)
fmt.Println("\tcreate\t", apppath + string(path.Separator))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "conf") + string(path.Separator))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "controllers") + string(path.Separator))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "models") + string(path.Separator))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "routers") + string(path.Separator))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "tests") + string(path.Separator))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "static") + string(path.Separator))
fmt.Fprintf(w, "\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)
fmt.Println("\tcreate\t", path.Join(apppath, "static", "js") + string(path.Separator))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "static", "css") + string(path.Separator))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "static", "img") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "views") + string(path.Separator))
fmt.Fprintf(w, "\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(w, "\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.Println("\tcreate\t", path.Join(apppath, "conf", "app.conf"))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "controllers", "default.go"))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "views", "index.tpl"))
fmt.Fprintf(w, "\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.Println("\tcreate\t", path.Join(apppath, "routers", "router.go"))
fmt.Fprintf(w, "\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}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1))
fmt.Println("\tcreate\t", path.Join(apppath, "tests", "default_test.go"))
fmt.Fprintf(w, "\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}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1))
fmt.Println("\tcreate\t", path.Join(apppath, "main.go"))
fmt.Fprintf(w, "\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}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1))
ColorLog("[SUCC] New application successfully created!\n")
@ -309,9 +313,10 @@ var indextpl = `<!DOCTYPE html>
</html>
`
// WriteToFile creates a file and writes content to it
func WriteToFile(filename, content string) {
f, err := os.Create(filename)
defer f.Close()
defer CloseFile(f)
if err != nil {
panic(err)
}

10
pack.go
View File

@ -72,6 +72,7 @@ var (
buildEnvs ListOpts
verbose bool
format string
w io.Writer
)
type ListOpts []string
@ -101,6 +102,7 @@ func init() {
fs.BoolVar(&verbose, "v", false, "verbose")
cmdPack.Flag = *fs
cmdPack.Run = packApp
w = NewColorWriter(os.Stdout)
}
func exitPrint(con string) {
@ -242,7 +244,7 @@ func (wft *walkFileTree) walkLeaf(fpath string, fi os.FileInfo, err error) error
if added, err := wft.wak.compress(name, fpath, fi); added {
if verbose {
fmt.Printf("\t+ Compressed: %s\n", name)
fmt.Fprintf(w, "\t%s%scompressed%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", name, "\x1b[0m")
}
wft.allfiles[name] = true
return err
@ -338,7 +340,7 @@ func (wft *tarWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) {
if err != nil {
return false, err
}
defer fr.Close()
defer CloseFile(fr)
_, err = io.Copy(tw, fr)
if err != nil {
return false, err
@ -374,7 +376,7 @@ func (wft *zipWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) {
if err != nil {
return false, err
}
defer fr.Close()
defer CloseFile(fr)
_, err = io.Copy(w, fr)
if err != nil {
return false, err
@ -559,7 +561,7 @@ func packApp(cmd *Command, args []string) int {
}
if verbose {
fmt.Println("\t+ go", strings.Join(args, " "))
fmt.Fprintf(w, "\t%s%s+ go %s%s%s\n", "\x1b[32m", "\x1b[1m", strings.Join(args, " "), "\x1b[21m", "\x1b[0m")
}
execmd := exec.Command("go", args...)

View File

@ -287,3 +287,11 @@ 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) {
if err := f.Close(); err != nil {
panic(err)
}
}

View File

@ -2,54 +2,47 @@ package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
path "path/filepath"
"regexp"
"bytes"
)
var cmdVersion = &Command{
UsageLine: "version",
Short: "show the Bee, Beego and Go version",
Short: "prints the current Bee version",
Long: `
show the Bee, Beego and Go version
bee version
bee :1.2.3
beego :1.4.2
Go :go version go1.3.3 linux/amd64
Prints the current Bee, Beego and Go version alongside the platform information
`,
}
const verboseVersionBanner =
`______
const verboseVersionBanner string = `%s%s______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v{{ .BeeVersion }}
Beego : {{ .BeegoVersion }}
GoVersion : {{ .GoVersion }}
GOOS : {{ .GOOS }}
GOARCH : {{ .GOARCH }}
NumCPU : {{ .NumCPU }}
GOPATH : {{ .GOPATH }}
GOROOT : {{ .GOROOT }}
Compiler : {{ .Compiler }}
Date : {{ Now "Monday, 2 Jan 2006" }}
\____/ \___| \___| v{{ .BeeVersion }}%s
%s%s
Beego : {{ .BeegoVersion }}
GoVersion : {{ .GoVersion }}
GOOS : {{ .GOOS }}
GOARCH : {{ .GOARCH }}
NumCPU : {{ .NumCPU }}
GOPATH : {{ .GOPATH }}
GOROOT : {{ .GOROOT }}
Compiler : {{ .Compiler }}
Date : {{ Now "Monday, 2 Jan 2006" }}%s
`
const shortVersionBanner =
`______
const shortVersionBanner = `%s%s______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v{{ .BeeVersion }}
\____/ \___| \___| v{{ .BeeVersion }}%s
`
func init() {
@ -61,12 +54,19 @@ func versionCmd(cmd *Command, args []string) int {
return 0
}
// ShowVerboseVersionBanner prints the verbose version banner
func ShowVerboseVersionBanner() {
InitBanner(os.Stdout, bytes.NewBufferString(verboseVersionBanner))
w := NewColorWriter(os.Stdout)
coloredBanner := fmt.Sprintf(verboseVersionBanner, "\x1b[35m", "\x1b[1m", "\x1b[0m",
"\x1b[32m", "\x1b[1m", "\x1b[0m")
InitBanner(w, bytes.NewBufferString(coloredBanner))
}
// ShowShortVersionBanner prints the short version banner
func ShowShortVersionBanner() {
InitBanner(os.Stdout, bytes.NewBufferString(shortVersionBanner))
w := NewColorWriter(os.Stdout)
coloredBanner := fmt.Sprintf(shortVersionBanner, "\x1b[35m", "\x1b[1m", "\x1b[0m")
InitBanner(w, bytes.NewBufferString(coloredBanner))
}
func getBeegoVersion() string {