2013-09-03 17:23:58 +00:00
|
|
|
|
// Copyright 2013 bee authors
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
|
|
|
|
// not use this file except in compliance with the License. You may obtain
|
|
|
|
|
// a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
|
// License for the specific language governing permissions and limitations
|
|
|
|
|
// under the License.
|
|
|
|
|
|
2017-03-06 23:58:53 +00:00
|
|
|
|
package utils
|
2013-07-06 07:30:57 +00:00
|
|
|
|
|
2013-08-09 14:40:46 +00:00
|
|
|
|
import (
|
2016-12-03 10:46:10 +00:00
|
|
|
|
"bytes"
|
2020-08-02 15:02:12 +00:00
|
|
|
|
"encoding/json"
|
2016-09-26 18:25:15 +00:00
|
|
|
|
"fmt"
|
|
|
|
|
"io/ioutil"
|
2020-08-02 15:02:12 +00:00
|
|
|
|
"net/http"
|
2013-08-09 14:40:46 +00:00
|
|
|
|
"os"
|
2016-11-13 13:12:38 +00:00
|
|
|
|
"os/exec"
|
2016-09-26 18:25:15 +00:00
|
|
|
|
"path"
|
2013-08-09 14:40:46 +00:00
|
|
|
|
"path/filepath"
|
2016-09-26 18:25:15 +00:00
|
|
|
|
"regexp"
|
2013-08-09 14:40:46 +00:00
|
|
|
|
"runtime"
|
2020-08-01 09:12:09 +00:00
|
|
|
|
"strconv"
|
2013-10-30 23:39:44 +00:00
|
|
|
|
"strings"
|
2016-12-03 10:46:10 +00:00
|
|
|
|
"text/template"
|
2017-04-02 21:36:17 +00:00
|
|
|
|
"time"
|
2017-03-21 14:29:29 +00:00
|
|
|
|
"unicode"
|
2017-03-06 23:58:53 +00:00
|
|
|
|
|
2020-08-02 08:17:02 +00:00
|
|
|
|
"github.com/beego/bee/config"
|
|
|
|
|
"github.com/beego/bee/internal/pkg/system"
|
2017-03-06 23:58:53 +00:00
|
|
|
|
beeLogger "github.com/beego/bee/logger"
|
|
|
|
|
"github.com/beego/bee/logger/colors"
|
2013-08-09 14:40:46 +00:00
|
|
|
|
)
|
2013-07-06 07:30:57 +00:00
|
|
|
|
|
2020-08-02 15:02:12 +00:00
|
|
|
|
type tagName struct {
|
2020-10-09 15:33:58 +00:00
|
|
|
|
Name string `json:"name"`
|
2020-08-02 15:02:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-25 14:29:27 +00:00
|
|
|
|
func GetBeeWorkPath() string {
|
2020-07-24 07:54:52 +00:00
|
|
|
|
curpath, err := os.Getwd()
|
2020-06-25 14:29:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2020-07-24 07:54:52 +00:00
|
|
|
|
return curpath
|
2020-06-25 14:29:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-07-06 07:30:57 +00:00
|
|
|
|
// Go is a basic promise implementation: it wraps calls a function in a goroutine
|
|
|
|
|
// and returns a channel which will later return the function's return value.
|
|
|
|
|
func Go(f func() error) chan error {
|
|
|
|
|
ch := make(chan error)
|
|
|
|
|
go func() {
|
|
|
|
|
ch <- f()
|
|
|
|
|
}()
|
|
|
|
|
return ch
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-30 23:39:44 +00:00
|
|
|
|
// IsExist returns whether a file or directory exists.
|
2017-03-06 23:58:53 +00:00
|
|
|
|
func IsExist(path string) bool {
|
2013-10-30 23:39:44 +00:00
|
|
|
|
_, err := os.Stat(path)
|
|
|
|
|
return err == nil || os.IsExist(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetGOPATHs returns all paths in GOPATH variable.
|
|
|
|
|
func GetGOPATHs() []string {
|
|
|
|
|
gopath := os.Getenv("GOPATH")
|
2017-04-24 12:10:52 +00:00
|
|
|
|
if gopath == "" && strings.Compare(runtime.Version(), "go1.8") >= 0 {
|
|
|
|
|
gopath = defaultGOPATH()
|
|
|
|
|
}
|
2017-04-19 16:26:25 +00:00
|
|
|
|
return filepath.SplitList(gopath)
|
2013-10-30 23:39:44 +00:00
|
|
|
|
}
|
2014-08-09 03:14:00 +00:00
|
|
|
|
|
2017-03-24 07:54:17 +00:00
|
|
|
|
// IsInGOPATH checks whether the path is inside of any GOPATH or not
|
2017-03-10 09:49:58 +00:00
|
|
|
|
func IsInGOPATH(thePath string) bool {
|
2017-03-24 07:54:17 +00:00
|
|
|
|
for _, gopath := range GetGOPATHs() {
|
2017-04-24 12:10:52 +00:00
|
|
|
|
if strings.Contains(thePath, filepath.Join(gopath, "src")) {
|
2017-03-24 07:54:17 +00:00
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
2017-03-10 09:49:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-21 14:23:08 +00:00
|
|
|
|
// IsBeegoProject checks whether the current path is a Beego application or not
|
|
|
|
|
func IsBeegoProject(thePath string) bool {
|
2016-09-26 18:25:15 +00:00
|
|
|
|
mainFiles := []string{}
|
2020-12-14 05:08:47 +00:00
|
|
|
|
hasBeegoRegex := regexp.MustCompile(`(?s)package main.*?import.*?\(.*?github.com/beego/beego/v2".*?\).*func main()`)
|
2016-11-20 10:55:44 +00:00
|
|
|
|
c := make(chan error)
|
2016-09-26 18:25:15 +00:00
|
|
|
|
// Walk the application path tree to look for main files.
|
|
|
|
|
// Main files must satisfy the 'hasBeegoRegex' regular expression.
|
2016-11-20 10:55:44 +00:00
|
|
|
|
go func() {
|
|
|
|
|
filepath.Walk(thePath, func(fpath string, f os.FileInfo, err error) error {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil
|
2016-09-26 18:25:15 +00:00
|
|
|
|
}
|
2016-11-20 10:55:44 +00:00
|
|
|
|
// Skip sub-directories
|
|
|
|
|
if !f.IsDir() {
|
|
|
|
|
var data []byte
|
|
|
|
|
data, err = ioutil.ReadFile(fpath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c <- err
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(hasBeegoRegex.Find(data)) > 0 {
|
|
|
|
|
mainFiles = append(mainFiles, fpath)
|
|
|
|
|
}
|
2016-09-26 18:25:15 +00:00
|
|
|
|
}
|
2016-11-20 10:55:44 +00:00
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
close(c)
|
|
|
|
|
}()
|
2016-09-26 18:25:15 +00:00
|
|
|
|
|
2016-11-20 10:55:44 +00:00
|
|
|
|
if err := <-c; err != nil {
|
2017-03-06 23:58:53 +00:00
|
|
|
|
beeLogger.Log.Fatalf("Unable to walk '%s' tree: %s", thePath, err)
|
2016-09-26 18:25:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(mainFiles) > 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SearchGOPATHs searchs the user GOPATH(s) for the specified application name.
|
|
|
|
|
// It returns a boolean, the application's GOPATH and its full path.
|
2016-07-29 15:45:15 +00:00
|
|
|
|
func SearchGOPATHs(app string) (bool, string, string) {
|
|
|
|
|
gps := GetGOPATHs()
|
|
|
|
|
if len(gps) == 0 {
|
2017-03-06 23:58:53 +00:00
|
|
|
|
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
|
2016-07-29 15:45:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lookup the application inside the user workspace(s)
|
|
|
|
|
for _, gopath := range gps {
|
|
|
|
|
var currentPath string
|
|
|
|
|
|
|
|
|
|
if !strings.Contains(app, "src") {
|
|
|
|
|
gopathsrc := path.Join(gopath, "src")
|
|
|
|
|
currentPath = path.Join(gopathsrc, app)
|
|
|
|
|
} else {
|
|
|
|
|
currentPath = app
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-06 23:58:53 +00:00
|
|
|
|
if IsExist(currentPath) {
|
2016-07-29 15:45:15 +00:00
|
|
|
|
return true, gopath, currentPath
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false, "", ""
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-09 03:14:00 +00:00
|
|
|
|
// askForConfirmation uses Scanln to parse user input. A user must type in "yes" or "no" and
|
|
|
|
|
// then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as
|
|
|
|
|
// 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)")
|
2017-03-06 23:58:53 +00:00
|
|
|
|
func AskForConfirmation() bool {
|
2014-08-09 03:14:00 +00:00
|
|
|
|
var response string
|
|
|
|
|
_, err := fmt.Scanln(&response)
|
|
|
|
|
if err != nil {
|
2017-03-06 23:58:53 +00:00
|
|
|
|
beeLogger.Log.Fatalf("%s", err)
|
2014-08-09 03:14:00 +00:00
|
|
|
|
}
|
|
|
|
|
okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
|
|
|
|
|
nokayResponses := []string{"n", "N", "no", "No", "NO"}
|
|
|
|
|
if containsString(okayResponses, response) {
|
|
|
|
|
return true
|
|
|
|
|
} else if containsString(nokayResponses, response) {
|
|
|
|
|
return false
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Println("Please type yes or no and then press enter:")
|
2017-03-06 23:58:53 +00:00
|
|
|
|
return AskForConfirmation()
|
2014-08-09 03:14:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func containsString(slice []string, element string) bool {
|
|
|
|
|
for _, elem := range slice {
|
|
|
|
|
if elem == element {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
2014-08-18 03:51:57 +00:00
|
|
|
|
|
|
|
|
|
// snake string, XxYy to xx_yy
|
2017-03-06 23:58:53 +00:00
|
|
|
|
func SnakeString(s string) string {
|
2014-08-18 03:51:57 +00:00
|
|
|
|
data := make([]byte, 0, len(s)*2)
|
|
|
|
|
j := false
|
|
|
|
|
num := len(s)
|
|
|
|
|
for i := 0; i < num; i++ {
|
|
|
|
|
d := s[i]
|
|
|
|
|
if i > 0 && d >= 'A' && d <= 'Z' && j {
|
|
|
|
|
data = append(data, '_')
|
|
|
|
|
}
|
|
|
|
|
if d != '_' {
|
|
|
|
|
j = true
|
|
|
|
|
}
|
|
|
|
|
data = append(data, d)
|
|
|
|
|
}
|
2016-11-13 13:12:38 +00:00
|
|
|
|
return strings.ToLower(string(data[:]))
|
2014-08-18 03:51:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-06 23:58:53 +00:00
|
|
|
|
func CamelString(s string) string {
|
2014-08-18 03:51:57 +00:00
|
|
|
|
data := make([]byte, 0, len(s))
|
|
|
|
|
j := false
|
|
|
|
|
k := false
|
|
|
|
|
num := len(s) - 1
|
|
|
|
|
for i := 0; i <= num; i++ {
|
|
|
|
|
d := s[i]
|
2017-03-06 23:58:53 +00:00
|
|
|
|
if !k && d >= 'A' && d <= 'Z' {
|
2014-08-18 03:51:57 +00:00
|
|
|
|
k = true
|
|
|
|
|
}
|
2017-03-06 23:58:53 +00:00
|
|
|
|
if d >= 'a' && d <= 'z' && (j || !k) {
|
2014-08-18 03:51:57 +00:00
|
|
|
|
d = d - 32
|
|
|
|
|
j = false
|
|
|
|
|
k = true
|
|
|
|
|
}
|
|
|
|
|
if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
|
|
|
|
|
j = true
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
data = append(data, d)
|
|
|
|
|
}
|
2016-11-13 13:12:38 +00:00
|
|
|
|
return string(data[:])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// camelCase converts a _ delimited string to camel case
|
|
|
|
|
// e.g. very_important_person => VeryImportantPerson
|
2017-03-06 23:58:53 +00:00
|
|
|
|
func CamelCase(in string) string {
|
2016-11-13 13:12:38 +00:00
|
|
|
|
tokens := strings.Split(in, "_")
|
|
|
|
|
for i := range tokens {
|
|
|
|
|
tokens[i] = strings.Title(strings.Trim(tokens[i], " "))
|
|
|
|
|
}
|
|
|
|
|
return strings.Join(tokens, "")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// formatSourceCode formats source files
|
2017-03-06 23:58:53 +00:00
|
|
|
|
func FormatSourceCode(filename string) {
|
2016-11-13 13:12:38 +00:00
|
|
|
|
cmd := exec.Command("gofmt", "-w", filename)
|
|
|
|
|
if err := cmd.Run(); err != nil {
|
2017-03-06 23:58:53 +00:00
|
|
|
|
beeLogger.Log.Warnf("Error while running gofmt: %s", err)
|
2016-11-13 13:12:38 +00:00
|
|
|
|
}
|
2014-08-18 03:51:57 +00:00
|
|
|
|
}
|
2015-06-17 06:59:59 +00:00
|
|
|
|
|
2016-07-31 21:30:35 +00:00
|
|
|
|
// CloseFile attempts to close the passed file
|
|
|
|
|
// or panics with the actual error
|
|
|
|
|
func CloseFile(f *os.File) {
|
2016-11-13 13:12:38 +00:00
|
|
|
|
err := f.Close()
|
|
|
|
|
MustCheck(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MustCheck panics when the error is not nil
|
|
|
|
|
func MustCheck(err error) {
|
|
|
|
|
if err != nil {
|
2016-07-31 21:30:35 +00:00
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-13 13:12:38 +00:00
|
|
|
|
|
|
|
|
|
// WriteToFile creates a file and writes content to it
|
|
|
|
|
func WriteToFile(filename, content string) {
|
|
|
|
|
f, err := os.Create(filename)
|
|
|
|
|
MustCheck(err)
|
|
|
|
|
defer CloseFile(f)
|
|
|
|
|
_, err = f.WriteString(content)
|
|
|
|
|
MustCheck(err)
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-14 17:02:29 +00:00
|
|
|
|
// __FILE__ returns the file name in which the function was invoked
|
2017-03-06 23:58:53 +00:00
|
|
|
|
func FILE() string {
|
2016-11-14 17:02:29 +00:00
|
|
|
|
_, file, _, _ := runtime.Caller(1)
|
|
|
|
|
return file
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// __LINE__ returns the line number at which the function was invoked
|
2017-03-06 23:58:53 +00:00
|
|
|
|
func LINE() int {
|
2016-11-14 17:02:29 +00:00
|
|
|
|
_, _, line, _ := runtime.Caller(1)
|
|
|
|
|
return line
|
|
|
|
|
}
|
2016-12-03 10:46:10 +00:00
|
|
|
|
|
|
|
|
|
// BeeFuncMap returns a FuncMap of functions used in different templates.
|
|
|
|
|
func BeeFuncMap() template.FuncMap {
|
|
|
|
|
return template.FuncMap{
|
2016-12-03 15:06:46 +00:00
|
|
|
|
"trim": strings.TrimSpace,
|
2017-03-06 23:58:53 +00:00
|
|
|
|
"bold": colors.Bold,
|
|
|
|
|
"headline": colors.MagentaBold,
|
|
|
|
|
"foldername": colors.RedBold,
|
2016-12-03 15:06:46 +00:00
|
|
|
|
"endline": EndLine,
|
|
|
|
|
"tmpltostr": TmplToString,
|
2016-12-03 10:46:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TmplToString parses a text template and return the result as a string.
|
|
|
|
|
func TmplToString(tmpl string, data interface{}) string {
|
|
|
|
|
t := template.New("tmpl").Funcs(BeeFuncMap())
|
|
|
|
|
template.Must(t.Parse(tmpl))
|
|
|
|
|
|
|
|
|
|
var doc bytes.Buffer
|
|
|
|
|
err := t.Execute(&doc, data)
|
|
|
|
|
MustCheck(err)
|
|
|
|
|
|
|
|
|
|
return doc.String()
|
|
|
|
|
}
|
2017-03-06 23:58:53 +00:00
|
|
|
|
|
|
|
|
|
// 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 {
|
2020-07-24 07:54:52 +00:00
|
|
|
|
beeLogger.Log.Error("if you want new a go module project,please add param `-gopath=false`.")
|
2017-03-06 23:58:53 +00:00
|
|
|
|
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
|
|
|
|
|
}
|
|
|
|
|
currpath, _ := os.Getwd()
|
2017-04-19 16:26:25 +00:00
|
|
|
|
currpath = filepath.Join(currpath, appname)
|
2017-03-06 23:58:53 +00:00
|
|
|
|
for _, gpath := range gps {
|
2017-04-19 16:26:25 +00:00
|
|
|
|
gsrcpath := filepath.Join(gpath, "src")
|
|
|
|
|
if strings.HasPrefix(strings.ToLower(currpath), strings.ToLower(gsrcpath)) {
|
2017-03-06 23:58:53 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2017-04-19 16:26:25 +00:00
|
|
|
|
gosrcpath := filepath.Join(gopath, "src")
|
|
|
|
|
apppath = filepath.Join(gosrcpath, appname)
|
2017-03-06 23:58:53 +00:00
|
|
|
|
|
|
|
|
|
if _, e := os.Stat(apppath); !os.IsNotExist(e) {
|
2019-01-07 18:08:03 +00:00
|
|
|
|
err = fmt.Errorf("cannot create application without removing '%s' first", apppath)
|
2017-03-06 23:58:53 +00:00
|
|
|
|
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)
|
|
|
|
|
}
|
2017-03-21 14:29:29 +00:00
|
|
|
|
|
|
|
|
|
// GoCommand executes the passed command using Go tool
|
|
|
|
|
func GoCommand(command string, args ...string) error {
|
|
|
|
|
allargs := []string{command}
|
|
|
|
|
allargs = append(allargs, args...)
|
|
|
|
|
goBuild := exec.Command("go", allargs...)
|
|
|
|
|
goBuild.Stderr = os.Stderr
|
|
|
|
|
return goBuild.Run()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SplitQuotedFields is like strings.Fields but ignores spaces
|
|
|
|
|
// inside areas surrounded by single quotes.
|
|
|
|
|
// To specify a single quote use backslash to escape it: '\''
|
|
|
|
|
func SplitQuotedFields(in string) []string {
|
|
|
|
|
type stateEnum int
|
|
|
|
|
const (
|
|
|
|
|
inSpace stateEnum = iota
|
|
|
|
|
inField
|
|
|
|
|
inQuote
|
|
|
|
|
inQuoteEscaped
|
|
|
|
|
)
|
|
|
|
|
state := inSpace
|
|
|
|
|
r := []string{}
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
|
|
|
|
for _, ch := range in {
|
|
|
|
|
switch state {
|
|
|
|
|
case inSpace:
|
|
|
|
|
if ch == '\'' {
|
|
|
|
|
state = inQuote
|
|
|
|
|
} else if !unicode.IsSpace(ch) {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
state = inField
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case inField:
|
|
|
|
|
if ch == '\'' {
|
|
|
|
|
state = inQuote
|
|
|
|
|
} else if unicode.IsSpace(ch) {
|
|
|
|
|
r = append(r, buf.String())
|
|
|
|
|
buf.Reset()
|
|
|
|
|
} else {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case inQuote:
|
|
|
|
|
if ch == '\'' {
|
|
|
|
|
state = inField
|
|
|
|
|
} else if ch == '\\' {
|
|
|
|
|
state = inQuoteEscaped
|
|
|
|
|
} else {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case inQuoteEscaped:
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
state = inQuote
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if buf.Len() != 0 {
|
|
|
|
|
r = append(r, buf.String())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r
|
|
|
|
|
}
|
2017-04-02 21:36:17 +00:00
|
|
|
|
|
|
|
|
|
// GetFileModTime returns unix timestamp of `os.File.ModTime` for the given path.
|
|
|
|
|
func GetFileModTime(path string) int64 {
|
|
|
|
|
path = strings.Replace(path, "\\", "/", -1)
|
|
|
|
|
f, err := os.Open(path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
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 {
|
|
|
|
|
beeLogger.Log.Errorf("Failed to get file stats: %s", err)
|
|
|
|
|
return time.Now().Unix()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fi.ModTime().Unix()
|
|
|
|
|
}
|
2017-04-24 12:10:52 +00:00
|
|
|
|
|
|
|
|
|
func defaultGOPATH() string {
|
|
|
|
|
env := "HOME"
|
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
|
env = "USERPROFILE"
|
|
|
|
|
} else if runtime.GOOS == "plan9" {
|
|
|
|
|
env = "home"
|
|
|
|
|
}
|
|
|
|
|
if home := os.Getenv(env); home != "" {
|
|
|
|
|
return filepath.Join(home, "go")
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
2020-07-11 04:29:24 +00:00
|
|
|
|
|
|
|
|
|
func GetGoVersionSkipMinor() string {
|
|
|
|
|
strArray := strings.Split(runtime.Version()[2:], `.`)
|
|
|
|
|
return strArray[0] + `.` + strArray[1]
|
|
|
|
|
}
|
2020-07-11 05:02:25 +00:00
|
|
|
|
|
|
|
|
|
func IsGOMODULE() bool {
|
|
|
|
|
if combinedOutput, e := exec.Command(`go`, `env`).CombinedOutput(); e != nil {
|
|
|
|
|
beeLogger.Log.Errorf("i cann't find go.")
|
|
|
|
|
} else {
|
|
|
|
|
regex := regexp.MustCompile(`GOMOD="?(.+go.mod)"?`)
|
|
|
|
|
stringSubmatch := regex.FindStringSubmatch(string(combinedOutput))
|
|
|
|
|
return len(stringSubmatch) == 2
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
2020-08-01 09:12:09 +00:00
|
|
|
|
|
2020-08-02 08:17:02 +00:00
|
|
|
|
func NoticeUpdateBee() {
|
2020-08-01 09:12:09 +00:00
|
|
|
|
cmd := exec.Command("go", "version")
|
|
|
|
|
cmd.Output()
|
|
|
|
|
if cmd.Process == nil || cmd.Process.Pid <= 0 {
|
|
|
|
|
beeLogger.Log.Warn("There is no go environment")
|
|
|
|
|
return
|
|
|
|
|
}
|
2020-08-02 08:17:02 +00:00
|
|
|
|
beeHome := system.BeegoHome
|
2020-08-10 14:46:29 +00:00
|
|
|
|
if !IsExist(beeHome) {
|
|
|
|
|
if err := os.MkdirAll(beeHome, 0755); err != nil {
|
|
|
|
|
beeLogger.Log.Fatalf("Could not create the directory: %s", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-02 08:17:02 +00:00
|
|
|
|
fp := beeHome + "/.noticeUpdateBee"
|
2020-08-01 09:12:09 +00:00
|
|
|
|
timeNow := time.Now().Unix()
|
|
|
|
|
var timeOld int64
|
2020-08-02 08:17:02 +00:00
|
|
|
|
if !IsExist(fp) {
|
|
|
|
|
f, err := os.Create(fp)
|
2020-08-01 09:12:09 +00:00
|
|
|
|
if err != nil {
|
2020-08-02 08:17:02 +00:00
|
|
|
|
beeLogger.Log.Warnf("Create noticeUpdateBee file err: %s", err)
|
|
|
|
|
return
|
2020-08-01 09:12:09 +00:00
|
|
|
|
}
|
2020-08-02 08:17:02 +00:00
|
|
|
|
defer f.Close()
|
2020-08-01 09:12:09 +00:00
|
|
|
|
}
|
2020-08-02 08:17:02 +00:00
|
|
|
|
oldContent, err := ioutil.ReadFile(fp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
beeLogger.Log.Warnf("Read noticeUpdateBee file err: %s", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
timeOld, _ = strconv.ParseInt(string(oldContent), 10, 64)
|
|
|
|
|
if timeNow-timeOld < 24*60*60 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
w, err := os.OpenFile(fp, os.O_WRONLY|os.O_TRUNC, 0644)
|
|
|
|
|
if err != nil {
|
|
|
|
|
beeLogger.Log.Warnf("Open noticeUpdateBee file err: %s", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer w.Close()
|
|
|
|
|
timeNowStr := strconv.FormatInt(timeNow, 10)
|
|
|
|
|
if _, err := w.WriteString(timeNowStr); err != nil {
|
|
|
|
|
beeLogger.Log.Warnf("Update noticeUpdateBee file err: %s", err)
|
|
|
|
|
return
|
2020-08-01 09:12:09 +00:00
|
|
|
|
}
|
2020-08-02 15:02:12 +00:00
|
|
|
|
beeLogger.Log.Info("Getting bee latest version...")
|
|
|
|
|
versionLast := BeeLastVersion()
|
|
|
|
|
versionNow := config.Version
|
2020-10-09 15:33:58 +00:00
|
|
|
|
if versionLast == "" {
|
2020-08-02 15:02:12 +00:00
|
|
|
|
beeLogger.Log.Warn("Get latest version err")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if versionNow != versionLast {
|
|
|
|
|
beeLogger.Log.Warnf("Update available %s ==> %s", versionNow, versionLast)
|
|
|
|
|
beeLogger.Log.Warn("Run `bee update` to update")
|
|
|
|
|
}
|
|
|
|
|
beeLogger.Log.Info("Your bee are up to date")
|
2020-08-01 09:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-02 15:02:12 +00:00
|
|
|
|
func BeeLastVersion() (version string) {
|
|
|
|
|
var url = "https://api.github.com/repos/beego/bee/tags"
|
|
|
|
|
resp, err := http.Get(url)
|
2020-08-02 08:17:02 +00:00
|
|
|
|
if err != nil {
|
2020-08-02 15:02:12 +00:00
|
|
|
|
beeLogger.Log.Warnf("Get bee tags from github error: %s", err)
|
2020-08-01 09:12:09 +00:00
|
|
|
|
return
|
2020-08-02 08:17:02 +00:00
|
|
|
|
}
|
2020-08-02 15:02:12 +00:00
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
bodyContent, _ := ioutil.ReadAll(resp.Body)
|
|
|
|
|
var tags []tagName
|
|
|
|
|
if err = json.Unmarshal(bodyContent, &tags); err != nil {
|
|
|
|
|
beeLogger.Log.Warnf("Unmarshal tags body error: %s", err)
|
2020-08-02 08:17:02 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
2020-08-02 15:02:12 +00:00
|
|
|
|
if len(tags) < 1 {
|
|
|
|
|
beeLogger.Log.Warn("There is no tags!")
|
|
|
|
|
return
|
2020-08-02 08:17:02 +00:00
|
|
|
|
}
|
2020-08-02 15:02:12 +00:00
|
|
|
|
last := tags[0]
|
|
|
|
|
re, _ := regexp.Compile(`[0-9.]+`)
|
|
|
|
|
versionList := re.FindStringSubmatch(last.Name)
|
|
|
|
|
if len(versionList) > 0 {
|
|
|
|
|
return versionList[0]
|
2020-08-01 09:12:09 +00:00
|
|
|
|
}
|
2020-08-02 15:02:12 +00:00
|
|
|
|
beeLogger.Log.Warn("There is no tags!")
|
|
|
|
|
return
|
2020-08-01 09:12:09 +00:00
|
|
|
|
}
|