From d99c24f2c29ea998aa216121189d213baf60300f Mon Sep 17 00:00:00 2001 From: Minho Date: Fri, 2 Jun 2017 16:08:14 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E4=BF=AE=E5=A4=8D=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E6=90=9C=E7=B4=A2=E6=97=A0=E6=B3=95=E6=9F=A5?= =?UTF-8?q?=E7=9C=8B=E7=9A=84BUG=202=E3=80=81=E6=96=B0=E5=A2=9E=E4=BB=A5?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=9A=84=E6=96=B9=E5=BC=8F=E5=90=AF=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appveyor.yml | 6 +- commands/command.go | 137 +++++++++++++++++++++++++++++--------- commands/daemon/daemon.go | 118 ++++++++++++++++++++++++++++++++ commands/install.go | 22 +++--- commands/update.go | 54 ++++++++------- database/data.sql | 17 ----- main.go | 29 +++++--- static/js/kancloud.js | 13 ++-- utils/file.go | 19 +++++- 9 files changed, 308 insertions(+), 107 deletions(-) create mode 100644 commands/daemon/daemon.go delete mode 100644 database/data.sql diff --git a/appveyor.yml b/appveyor.yml index 7a2147d6..f69b1f6f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,10 +38,10 @@ build_script: - if [%tbs_tools%]==[mingw] if [%tbs_arch%]==[x64] SET PATH=C:\mingw64\bin;%PATH% - set CGO_ENABLED=1 - go build -v -o "godoc_windows_%GOARCH%.exe" -ldflags="-w -X github.com/lifei6671/godoc/conf.VERSION=%APPVEYOR_REPO_TAG_NAME% -X 'github.com/lifei6671/godoc/conf.BUILD_TIME=`date`' -X 'conf.GO_VERSION=`github.com/lifei6671/godoc/go version`'" - - 7z a -t7z -r godoc_windows_%GOARCH%.7z conf/*.conf* static/* godoc_windows_%GOARCH%.exe views/* database/* logs/* uploads/* + - 7z a -t7z -r godoc_windows_%GOARCH%.7z conf/*.conf* static/* godoc_windows_%GOARCH%.exe views/* uploads/* test_script: - - godoc_windows_%GOARCH%.exe version - - dir + - if [%tbs_arch%]==[x86] godoc_windows_386.exe version + - if [%tbs_arch%]==[x64] godoc_windows_amd64.exe version notifications: - provider: Email diff --git a/commands/command.go b/commands/command.go index 020cc6cf..2708af4c 100644 --- a/commands/command.go +++ b/commands/command.go @@ -7,17 +7,26 @@ import ( "os" "time" + "flag" + "path/filepath" + "strings" + "github.com/astaxie/beego" "github.com/astaxie/beego/logs" "github.com/astaxie/beego/orm" "github.com/lifei6671/gocaptcha" + "github.com/lifei6671/godoc/commands/migrate" "github.com/lifei6671/godoc/conf" "github.com/lifei6671/godoc/models" - "strings" - "github.com/lifei6671/godoc/commands/migrate" - "path/filepath" + "github.com/lifei6671/godoc/utils" + "log" ) +var ( + ConfigurationFile = "./conf/app.conf" + WorkingDirectory = "./" + LogFile = "./logs" +) // RegisterDataBase 注册数据库 func RegisterDataBase() { @@ -40,12 +49,12 @@ func RegisterDataBase() { if err == nil { orm.DefaultTimeLoc = location } else { - fmt.Println(err) + log.Fatalln(err) } - }else if adapter == "sqlite3" { + } else if adapter == "sqlite3" { database := beego.AppConfig.String("db_database") dbPath := filepath.Dir(database) - os.MkdirAll(dbPath,0777) + os.MkdirAll(dbPath, 0777) orm.RegisterDataBase("default", "sqlite3", database) } @@ -69,19 +78,22 @@ func RegisterModel() { } // RegisterLogger 注册日志 -func RegisterLogger() { +func RegisterLogger(log string) { logs.SetLogFuncCall(true) logs.SetLogger("console") logs.EnableFuncCallDepth(true) logs.Async() - if _, err := os.Stat("logs/log.log"); os.IsNotExist(err) { - os.MkdirAll("./logs", 0777) + logPath := filepath.Join(log, "log.log") - if f, err := os.Create("logs/log.log"); err == nil { + if _, err := os.Stat(logPath); os.IsNotExist(err) { + + os.MkdirAll(log, 0777) + + if f, err := os.Create(logPath); err == nil { f.Close() - beego.SetLogger("file", `{"filename":"logs/log.log"}`) + beego.SetLogger("file", fmt.Sprintf(`{"filename":"%s"}`, logPath)) } } @@ -92,58 +104,121 @@ func RegisterLogger() { // RunCommand 注册orm命令行工具 func RegisterCommand() { - Install() - CheckUpdate() - migrate.RunMigration() + if len(os.Args) >= 2 && os.Args[1] == "install" { + ResolveCommand(os.Args[2:]) + Install() + } else if len(os.Args) >= 2 && os.Args[1] == "version" { + ResolveCommand(os.Args[2:]) + CheckUpdate() + } else if len(os.Args) >= 2 && os.Args[1] == "migrate" { + ResolveCommand(os.Args[2:]) + migrate.RunMigration() + } } func RegisterFunction() { beego.AddFuncMap("config", models.GetOptionValue) beego.AddFuncMap("cdn", func(p string) string { - cdn := beego.AppConfig.DefaultString("cdn","") - if strings.HasPrefix(p,"/") && strings.HasSuffix(cdn,"/"){ + cdn := beego.AppConfig.DefaultString("cdn", "") + if strings.HasPrefix(p, "/") && strings.HasSuffix(cdn, "/") { return cdn + string(p[1:]) } - if !strings.HasPrefix(p,"/") && !strings.HasSuffix(cdn,"/"){ + if !strings.HasPrefix(p, "/") && !strings.HasSuffix(cdn, "/") { return cdn + "/" + p } return cdn + p - }); + }) beego.AddFuncMap("cdnjs", func(p string) string { - cdn := beego.AppConfig.DefaultString("cdnjs","") - if strings.HasPrefix(p,"/") && strings.HasSuffix(cdn,"/"){ + cdn := beego.AppConfig.DefaultString("cdnjs", "") + if strings.HasPrefix(p, "/") && strings.HasSuffix(cdn, "/") { return cdn + string(p[1:]) } - if !strings.HasPrefix(p,"/") && !strings.HasSuffix(cdn,"/"){ + if !strings.HasPrefix(p, "/") && !strings.HasSuffix(cdn, "/") { return cdn + "/" + p } return cdn + p - }); - beego.AddFuncMap("cdncss", func(p string) string { - cdn := beego.AppConfig.DefaultString("cdncss","") - if strings.HasPrefix(p,"/") && strings.HasSuffix(cdn,"/"){ + }) + beego.AddFuncMap("cdncss", func(p string) string { + cdn := beego.AppConfig.DefaultString("cdncss", "") + if strings.HasPrefix(p, "/") && strings.HasSuffix(cdn, "/") { return cdn + string(p[1:]) } - if !strings.HasPrefix(p,"/") && !strings.HasSuffix(cdn,"/"){ + if !strings.HasPrefix(p, "/") && !strings.HasSuffix(cdn, "/") { return cdn + "/" + p } return cdn + p - }); + }) beego.AddFuncMap("cdnimg", func(p string) string { - cdn := beego.AppConfig.DefaultString("cdnimg","") - if strings.HasPrefix(p,"/") && strings.HasSuffix(cdn,"/"){ + cdn := beego.AppConfig.DefaultString("cdnimg", "") + if strings.HasPrefix(p, "/") && strings.HasSuffix(cdn, "/") { return cdn + string(p[1:]) } - if !strings.HasPrefix(p,"/") && !strings.HasSuffix(cdn,"/"){ + if !strings.HasPrefix(p, "/") && !strings.HasSuffix(cdn, "/") { return cdn + "/" + p } return cdn + p - }); + }) +} + +func ResolveCommand(args []string) { + flagSet := flag.NewFlagSet("MinDoc command: ", flag.ExitOnError) + flagSet.StringVar(&ConfigurationFile, "config", "", "MinDoc configuration file.") + flagSet.StringVar(&WorkingDirectory, "dir", "", "MinDoc working directory.") + flagSet.StringVar(&LogFile, "log", "", "MinDoc log file path.") + + flagSet.Parse(args) + + + if WorkingDirectory == "" { + if p, err := filepath.Abs(os.Args[0]); err == nil { + WorkingDirectory = filepath.Dir(p) + } + } + if LogFile == "" { + LogFile = filepath.Join(WorkingDirectory,"logs") + } + if ConfigurationFile == "" { + ConfigurationFile = filepath.Join(WorkingDirectory,"conf","app.conf") + config := filepath.Join(WorkingDirectory,"conf","app.conf.example") + if !utils.FileExists(ConfigurationFile) && utils.FileExists(config){ + utils.CopyFile(config,ConfigurationFile) + } + } + + err := beego.LoadAppConfig("ini", ConfigurationFile) + + if err != nil { + log.Println("An error occurred:", err) + os.Exit(1) + } + uploads := filepath.Join(WorkingDirectory, "uploads") + + os.MkdirAll(uploads,0666) + + beego.BConfig.WebConfig.StaticDir["/static"] = filepath.Join(WorkingDirectory, "static") + beego.BConfig.WebConfig.StaticDir["/uploads"] = uploads + beego.BConfig.WebConfig.ViewsPath = filepath.Join(WorkingDirectory, "views") + + fonts := filepath.Join(WorkingDirectory, "static", "fonts") + + if !utils.FileExists(fonts) { + log.Fatal("Font path not exist.") + } + gocaptcha.ReadFonts(filepath.Join(WorkingDirectory, "static", "fonts"), ".ttf") + + RegisterDataBase() + RegisterModel() + RegisterLogger(LogFile) } func init() { + gocaptcha.ReadFonts("./static/fonts", ".ttf") gob.Register(models.Member{}) + + if p,err := filepath.Abs(os.Args[0]);err == nil{ + WorkingDirectory = filepath.Dir(p) + } } diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go new file mode 100644 index 00000000..e81aca58 --- /dev/null +++ b/commands/daemon/daemon.go @@ -0,0 +1,118 @@ +package daemon + +import ( + "fmt" + "os" + + "github.com/astaxie/beego" + "github.com/kardianos/service" + "github.com/lifei6671/godoc/commands" + "github.com/lifei6671/godoc/conf" + "github.com/lifei6671/godoc/controllers" +) + +type Daemon struct { + config *service.Config + errs chan error +} + +func NewDaemon() *Daemon { + + config := &service.Config{ + Name: "MinDocService", //服务显示名称 + DisplayName: "MinDoc service", //服务名称 + Description: "A document online management program.", //服务描述 + WorkingDirectory: commands.WorkingDirectory, + Arguments: os.Args[1:], + } + + return &Daemon{ + config: config, + errs: make(chan error, 100), + } +} + +func (d *Daemon) Config() *service.Config { + return d.config +} +func (d *Daemon) Start(s service.Service) error { + + go d.Run() + return nil +} + +func (d *Daemon) Run() { + + commands.ResolveCommand(d.config.Arguments) + + commands.RegisterFunction() + + beego.ErrorController(&controllers.ErrorController{}) + + fmt.Printf("MinDoc version => %s\nbuild time => %s\nstart directory => %s\n%s\n", conf.VERSION, conf.BUILD_TIME, os.Args[0], conf.GO_VERSION) + + beego.Run() +} + +func (d *Daemon) Stop(s service.Service) error { + if service.Interactive() { + os.Exit(0) + } + return nil +} + +func Install() { + d := NewDaemon() + d.config.Arguments = os.Args[3:] + + s, err := service.New(d, d.config) + + if err != nil { + beego.Error("Create service error => ", err) + os.Exit(1) + } + err = s.Install() + if err != nil { + beego.Error("Install service error:", err) + os.Exit(1) + } else { + beego.Info("Service installed!") + } + + os.Exit(0) +} + +func Uninstall() { + d := NewDaemon() + s, err := service.New(d, d.config) + + if err != nil { + beego.Error("Create service error => ", err) + os.Exit(1) + } + err = s.Uninstall() + if err != nil { + beego.Error("Install service error:", err) + os.Exit(1) + } else { + beego.Info("Service uninstalled!") + } + os.Exit(0) +} + +func Restart() { + d := NewDaemon() + s, err := service.New(d, d.config) + + if err != nil { + beego.Error("Create service error => ", err) + os.Exit(1) + } + err = s.Restart() + if err != nil { + beego.Error("Install service error:", err) + os.Exit(1) + } else { + beego.Info("Service Restart!") + } +} diff --git a/commands/install.go b/commands/install.go index 739bc6ac..7fbc4fc8 100644 --- a/commands/install.go +++ b/commands/install.go @@ -12,19 +12,19 @@ import ( //系统安装. func Install() { - if len(os.Args) >= 2 && os.Args[1] == "install" { - fmt.Println("Initializing...") - err := orm.RunSyncdb("default", false, true) - if err == nil { - initialization() - } else { - panic(err.Error()) - os.Exit(1) - } - fmt.Println("Install Successfully!") - os.Exit(0) + fmt.Println("Initializing...") + + err := orm.RunSyncdb("default", false, true) + if err == nil { + initialization() + } else { + panic(err.Error()) + os.Exit(1) } + fmt.Println("Install Successfully!") + os.Exit(0) + } func Version() { diff --git a/commands/update.go b/commands/update.go index 42b0db13..154b7d90 100644 --- a/commands/update.go +++ b/commands/update.go @@ -14,34 +14,32 @@ import ( //检查最新版本. func CheckUpdate() { - if len(os.Args) >= 2 && os.Args[1] == "version" { + resp, err := http.Get("https://api.github.com/repos/lifei6671/godoc/tags") - resp, err := http.Get("https://api.github.com/repos/lifei6671/godoc/tags") - - if err != nil { - beego.Error("CheckUpdate => ", err) - os.Exit(1) - } - - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - beego.Error("CheckUpdate => ", err) - os.Exit(1) - } - - var result []*struct { - Name string `json:"name"` - } - - err = json.Unmarshal(body, &result) - - if err != nil { - beego.Error("CheckUpdate => ", err) - os.Exit(1) - } - fmt.Println("MinDoc current version => ", conf.VERSION) - fmt.Println("MinDoc last version => ", result[0].Name) - os.Exit(0) + if err != nil { + beego.Error("CheckUpdate => ", err) + os.Exit(1) } + + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + beego.Error("CheckUpdate => ", err) + os.Exit(1) + } + + var result []*struct { + Name string `json:"name"` + } + + err = json.Unmarshal(body, &result) + + if err != nil { + beego.Error("CheckUpdate => ", err) + os.Exit(1) + } + fmt.Println("MinDoc current version => ", conf.VERSION) + fmt.Println("MinDoc last version => ", result[0].Name) + os.Exit(0) + } diff --git a/database/data.sql b/database/data.sql deleted file mode 100644 index d1c81915..00000000 --- a/database/data.sql +++ /dev/null @@ -1,17 +0,0 @@ -INSERT INTO md_options (option_title, option_name, option_value) SELECT '是否启用注册','ENABLED_REGISTER','false' WHERE NOT exists(SELECT * FROM md_options WHERE option_name = 'ENABLED_REGISTER'); -INSERT INTO md_options (option_title, option_name, option_value) SELECT '是否启用文档历史','ENABLE_DOCUMENT_HISTORY','true' WHERE NOT exists(SELECT * FROM md_options WHERE option_name = 'ENABLE_DOCUMENT_HISTORY'); -INSERT INTO md_options (option_title, option_name, option_value) SELECT '是否启用验证码','ENABLED_CAPTCHA','false' WHERE NOT exists(SELECT * FROM md_options WHERE option_name = 'ENABLED_CAPTCHA'); -INSERT INTO md_options (option_title, option_name, option_value) SELECT '启用匿名访问','ENABLE_ANONYMOUS','true' WHERE NOT exists(SELECT * FROM md_options WHERE option_name = 'ENABLE_ANONYMOUS'); -INSERT INTO md_options (option_title, option_name, option_value) SELECT '站点名称','SITE_NAME','MinDoc' WHERE NOT exists(SELECT * FROM md_options WHERE option_name = 'SITE_NAME'); - - - - - - - - - - - - diff --git a/main.go b/main.go index c3a2cca3..5cd7eb8e 100644 --- a/main.go +++ b/main.go @@ -4,31 +4,38 @@ import ( "fmt" "os" - "github.com/astaxie/beego" _ "github.com/astaxie/beego/session/memcache" _ "github.com/astaxie/beego/session/mysql" _ "github.com/astaxie/beego/session/redis" _ "github.com/go-sql-driver/mysql" + "github.com/kardianos/service" "github.com/lifei6671/godoc/commands" - "github.com/lifei6671/godoc/conf" - "github.com/lifei6671/godoc/controllers" + "github.com/lifei6671/godoc/commands/daemon" _ "github.com/lifei6671/godoc/routers" _ "github.com/mattn/go-sqlite3" ) func main() { - commands.RegisterDataBase() - commands.RegisterModel() - commands.RegisterLogger() + if len(os.Args) >= 3 && os.Args[1] == "service" { + if os.Args[2] == "install" { + daemon.Install() + } else if os.Args[2] == "remove" { + daemon.Uninstall() + } else if os.Args[2] == "restart" { + daemon.Restart() + } + } commands.RegisterCommand() - commands.RegisterFunction() - beego.SetStaticPath("uploads", "uploads") + d := daemon.NewDaemon() - beego.ErrorController(&controllers.ErrorController{}) + s, err := service.New(d, d.Config()) - fmt.Printf("MinDoc version => %s\nbuild time => %s\nstart directory => %s\n%s\n", conf.VERSION, conf.BUILD_TIME, os.Args[0], conf.GO_VERSION) + if err != nil { + fmt.Println("Create service error => ", err) + os.Exit(1) + } - beego.Run() + s.Run() } diff --git a/static/js/kancloud.js b/static/js/kancloud.js index 1d10b833..a333e5ff 100644 --- a/static/js/kancloud.js +++ b/static/js/kancloud.js @@ -197,10 +197,13 @@ $(function () { console.log($param); } }; - - var $node = window.jsTree.jstree().get_selected(); - if(typeof $node === "object") { - $node = window.jsTree.jstree().get_node({ id : $node[0] }); - events.trigger('article.open',{ $url : $node.a_attr.href , $init : true, $id : $node.a_attr.id }); + try { + var $node = window.jsTree.jstree().get_selected(); + if (typeof $node === "object") { + $node = window.jsTree.jstree().get_node({id: $node[0]}); + events.trigger('article.open', {$url: $node.a_attr.href, $init: true, $id: $node.a_attr.id}); + } + }catch (e){ + console.log(e); } }); \ No newline at end of file diff --git a/utils/file.go b/utils/file.go index d413d5bb..0cb44e23 100644 --- a/utils/file.go +++ b/utils/file.go @@ -5,6 +5,7 @@ import ( "os" "fmt" "path/filepath" + "io" ) func AbsolutePath(p string) (string,error) { @@ -32,4 +33,20 @@ func FileExists(name string) bool { } } return true -} \ No newline at end of file +} + +func CopyFile(dstName, srcName string) (written int64, err error) { + src, err := os.Open(srcName) + if err != nil { + return + } + defer src.Close() + dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return + } + + defer dst.Close() + return io.Copy(dst, src) +} +