diff --git a/api.go b/api.go index 73a70c7..6e8c91a 100644 --- a/api.go +++ b/api.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "git.icechen.cn/pkg/wdt/util" "os" "git.icechen.cn/pkg/wdt/template/api/deploy" @@ -45,24 +46,56 @@ func ActionNewApi(c *cli.Context) error { appList := c.Args().Slice() if len(appList) == 0 { - appName := ReadLineWithMessage("请输入要创建的api名称: ") + appName := "" + for { + appName = util.ReadLineWithMessage("请输入要创建的api名称: ") + if appName != "" { + break + } else { + color.Red("应用名称不能为空!") + } + } appList = append(appList, appName) } for _, newApp := range appList { color.Green("正在创建[%s]API应用...", newApp) + app := config.Api.GetApp(newApp) + app = Api{ + Name: newApp, + Root: "app/api/" + newApp, + } - if ExistDir("app/api/"+newApp) && !ReadBoolWithMessage("app/api/"+newApp+"目录已存在,是否要覆盖app文件目录(y/n): ") { + if util.ExistDir(app.Root) && !util.ReadBoolWithMessage(app.Root+"目录已存在,是否要覆盖app文件目录(y/n): ") { return nil } - err := os.MkdirAll("app/api/"+newApp, os.ModePerm) + err := os.MkdirAll(app.Root, os.ModePerm) if err != nil { return err } - aliasName := ReadLineWithMessage("请输入应用的简短描述(别名): ") + app.AliasName = util.ReadLineWithMessage("请输入应用的简短描述(别名): ") + for { + app.Type = util.ReadLineWithMessage("请输入应用的类型(默认golang): ") + if app.Type == "golang" || app.Type == "" { + app.Type = "golang" + break + } else { + color.Red("暂不支持: [%s]类型", app.Type) + } + } + for { + app.Port = util.ReadLineWithMessage("请输入应用暴露的端口: ") + if app.Port != "" { + break + } else { + color.Red("端口号不能为空!") + } + } + app.Host = util.ReadLineWithMessage("请输入API应用请求的域名(host,如:api.seamlesser.com,建议为空): ") + app.Path = util.ReadLineWithMessage("请输入API应用请求的路由(path,如:/uwe/core/?(.*),建议为空): ") - err = deploy.GenDeploy(config.Name, newApp, aliasName) + err = deploy.GenDeploy(config.Name, newApp, app.AliasName) if err != nil { return err } @@ -72,6 +105,11 @@ func ActionNewApi(c *cli.Context) error { return err } + err = config.AppendAPI(app) + if err != nil { + return err + } + color.Green("[%s]API应用创建成功!!!\n\n", newApp) } return nil diff --git a/configFile.go b/configFile.go index 62ced34..4510037 100644 --- a/configFile.go +++ b/configFile.go @@ -1,6 +1,7 @@ package main import ( + "git.icechen.cn/pkg/wdt/util" "io/ioutil" "github.com/urfave/cli/v2" @@ -41,22 +42,24 @@ type Config struct { type ( ApiList []Api Api struct { - Name string `json:"name" yaml:"name"` - Root string `json:"root" yaml:"root"` - Type string `json:"type" yaml:"type"` - Port string `json:"port" yaml:"port"` - Host string `json:"host,omitempty" yaml:"host,omitempty"` - Path string `json:"path,omitempty" yaml:"path,omitempty"` + Name string `json:"name" yaml:"name"` + AliasName string `json:"alias_name" yaml:"aliasName"` + Root string `json:"root" yaml:"root"` + Type string `json:"type" yaml:"type"` + Port string `json:"port" yaml:"port"` + Host string `json:"host,omitempty" yaml:"host,omitempty"` + Path string `json:"path,omitempty" yaml:"path,omitempty"` } ) type ( ServiceList []Service Service struct { - Name string `json:"name" yaml:"name"` - Root string `json:"root" yaml:"root"` - Type string `json:"type" yaml:"type"` - Port string `json:"port" yaml:"port"` + Name string `json:"name" yaml:"name"` + AliasName string `json:"alias_name" yaml:"aliasName"` + Root string `json:"root" yaml:"root"` + Type string `json:"type" yaml:"type"` + Port string `json:"port" yaml:"port"` } ) @@ -74,15 +77,59 @@ func ReadConfig() error { return nil } -func (al ApiList) HasApp(appNameList []string) ApiList { - if len(appNameList) == 0 { - return al +func (c *Config) AppendAPI(api Api) error { + has := false + for i, a := range c.Api { + if a.Name == api.Name { + c.Api[i] = api + has = true + break + } } - hasApp := make(ApiList, 0, len(al)) + if !has { + c.Api = append(c.Api, api) + } + + out, err := yaml.Marshal(c) + if err != nil { + return err + } + + return util.WriteFileWithNotEdit(DefaultConfigFile, out) +} + +func (c *Config) AppendService(service Service) error { + has := false + for i, s := range c.Service { + if s.Name == service.Name { + c.Service[i] = service + has = true + break + } + } + + if !has { + c.Service = append(c.Service, service) + } + + out, err := yaml.Marshal(c) + if err != nil { + return err + } + + return util.WriteFileWithNotEdit(DefaultConfigFile, out) +} + +func (sl ApiList) HasApp(appNameList []string) ApiList { + if len(appNameList) == 0 { + return sl + } + + hasApp := make(ApiList, 0, len(sl)) al: - for _, api := range al { + for _, api := range sl { for _, a := range appNameList { if a == api.Name { hasApp = append(hasApp, api) @@ -93,6 +140,15 @@ al: return hasApp } +func (sl ApiList) GetApp(appName string) Api { + for _, api := range sl { + if api.Name == appName { + return api + } + } + return Api{} +} + func (sl ServiceList) HasApp(appNameList []string) ServiceList { if len(appNameList) == 0 { return sl @@ -111,3 +167,12 @@ sl: } return hasApp } + +func (sl ServiceList) GetApp(appName string) Service { + for _, service := range sl { + if service.Name == appName { + return service + } + } + return Service{} +} diff --git a/go.mod b/go.mod index 2fa7b1f..96740a5 100644 --- a/go.mod +++ b/go.mod @@ -3,21 +3,20 @@ module git.icechen.cn/pkg/wdt go 1.17 require ( + github.com/drone/drone-go v1.7.1 github.com/fatih/color v1.13.0 github.com/urfave/cli/v2 v2.3.0 + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) require ( github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect - github.com/drone/drone-go v1.7.1 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98 // indirect - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.27.1 // indirect diff --git a/go.sum b/go.sum index 603c806..60257d5 100644 --- a/go.sum +++ b/go.sum @@ -91,6 +91,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -110,10 +111,11 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -126,7 +128,6 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -244,16 +245,19 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -300,6 +304,7 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -381,6 +386,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/health.go b/health.go index 0547084..3a4461b 100644 --- a/health.go +++ b/health.go @@ -2,7 +2,7 @@ package main import ( "bytes" - "os" + "git.icechen.cn/pkg/wdt/util" ) type healthResp struct { @@ -22,13 +22,13 @@ func (hr healthResp) String() string { b := bytes.Buffer{} if !hr.Dir { - b.WriteString("\t\t应用目录:\t不存在") + b.WriteString("\t\t应用目录:\t不存在\n") } if !hr.Deploy { - b.WriteString("\t\t部署文件:\t不存在") + b.WriteString("\t\t部署文件(deploy):\t不存在\n") } if !hr.Dockerfile { - b.WriteString("\t\t构建文件:\t不存在") + b.WriteString("\t\t构建文件(Dockerfile):\t不存在\n") } return b.String() } @@ -41,20 +41,17 @@ func healthApi(api Api) healthResp { } // Dir 健康度 - info, err := os.Stat(api.Root) - if err == nil && info.IsDir() { + if util.ExistDir(api.Root) { ret.Dir = true } // Deploy 健康度 - info, err = os.Stat(api.Root + "/deploy") - if err == nil && info.IsDir() { + if util.ExistDir(api.Root + "/deploy") { ret.Deploy = true } // Dockerfile 健康度 - info, err = os.Stat(api.Root + "/Dockerfile") - if err == nil && !info.IsDir() { + if util.ExistFile(api.Root + "/Dockerfile") { ret.Dockerfile = true } diff --git a/template/api/docker/golang/golang.go b/template/api/docker/golang/golang.go index cd8dca3..6da958b 100644 --- a/template/api/docker/golang/golang.go +++ b/template/api/docker/golang/golang.go @@ -11,7 +11,14 @@ import ( //go:embed "Dockerfile.tpl" var dockerfileTemplate string +//go:embed "main.tpl" +var mainGoTemplate string + func GenDockerfile(name string) error { color.Green("正在生成dockerfile...") - return util.TemplateToFile("app/api/"+name+"/Dockerfile", dockerfileTemplate, map[string]string{"Name": name}) + err := util.TemplateToFile("app/api/"+name+"/Dockerfile", dockerfileTemplate, map[string]string{"Name": name}) + if err != nil { + return err + } + return util.TemplateToFile("app/api/"+name+"/main.go", mainGoTemplate, nil) } diff --git a/template/api/docker/golang/main.tpl b/template/api/docker/golang/main.tpl new file mode 100644 index 0000000..21ec4e8 --- /dev/null +++ b/template/api/docker/golang/main.tpl @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("我是个示例") +} diff --git a/util.go b/util.go index b37378e..06ab7d0 100644 --- a/util.go +++ b/util.go @@ -1,61 +1 @@ package main - -import ( - "bufio" - "fmt" - "os" - "strings" - - "github.com/fatih/color" -) - -func ReadBool() bool { - read := bufio.NewReader(os.Stdin) - ret, _ := read.ReadByte() - switch ret { - case 'y': - fallthrough - case 'Y': - return true - case 'n': - fallthrough - case 'N': - return false - } - return false -} - -func ReadBoolWithMessage(message string) bool { - NoNewLinePrint(color.HiRedString, message) - return ReadBool() -} - -func ReadLine() string { - read := bufio.NewReader(os.Stdin) - s, _ := read.ReadString('\n') - return s -} - -func ReadLineWithMessage(message string) string { - NoNewLinePrint(color.HiRedString, message) - return ReadLine() -} - -// ExistFile 文件是否存在 -func ExistFile(filePath string) bool { - info, err := os.Stat(filePath) - return err == nil && !info.IsDir() -} - -// ExistDir 目录是否存在 -func ExistDir(dirPath string) bool { - info, err := os.Stat(dirPath) - return err == nil && info.IsDir() -} - -func NoNewLinePrint(f func(format string, a ...interface{}) string, message string) { - if strings.HasSuffix(message, "\n") { - message = message[:len(message)-1] - } - fmt.Printf(f(message)) -} diff --git a/util/common.go b/util/common.go new file mode 100644 index 0000000..af1fab5 --- /dev/null +++ b/util/common.go @@ -0,0 +1,48 @@ +package util + +import ( + "bufio" + "fmt" + "github.com/fatih/color" + "os" + "strings" +) + +func ReadBool() bool { + read := bufio.NewReader(os.Stdin) + ret, _ := read.ReadByte() + switch ret { + case 'y': + fallthrough + case 'Y': + return true + case 'n': + fallthrough + case 'N': + return false + } + return false +} + +func ReadBoolWithMessage(message string) bool { + NoNewLinePrint(color.HiRedString, message) + return ReadBool() +} + +func ReadLine() string { + read := bufio.NewReader(os.Stdin) + s, _ := read.ReadString('\n') + return s[:len(s)-1] +} + +func ReadLineWithMessage(message string) string { + NoNewLinePrint(color.HiRedString, message) + return ReadLine() +} + +func NoNewLinePrint(f func(format string, a ...interface{}) string, message string) { + if strings.HasSuffix(message, "\n") { + message = message[:len(message)-1] + } + fmt.Printf(f(message)) +} diff --git a/util/file.go b/util/file.go index f6a3369..44e5ebd 100644 --- a/util/file.go +++ b/util/file.go @@ -31,3 +31,31 @@ func TemplateToFile(desFile string, templateContent string, data interface{}) er } return nil } + +func WriteFile(filePath string, data []byte) error { + file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm) + if err != nil { + return err + } + defer file.Close() + + _, err = file.Write(data) + return err +} + +func WriteFileWithNotEdit(filePath string, data []byte) error { + notEdit := "# Code generated by wujian-develop_tool. DO NOT EDIT.\n\n" + return WriteFile(filePath, []byte(notEdit+string(data))) +} + +// ExistFile 文件是否存在 +func ExistFile(filePath string) bool { + info, err := os.Stat(filePath) + return err == nil && !info.IsDir() +} + +// ExistDir 目录是否存在 +func ExistDir(dirPath string) bool { + info, err := os.Stat(dirPath) + return err == nil && info.IsDir() +}