diff --git a/conf/wide.json b/conf/wide.json index 8621716..ca1a835 100644 --- a/conf/wide.json +++ b/conf/wide.json @@ -11,13 +11,13 @@ "RuntimeMode": "dev", "Pwd": "{pwd}", "Workspace": "{pwd}/data/workspace", - "Locale": "zh_CN", + "Locale": "en_US", "Users": [ { "Name": "admin", "Password": "admin", "Workspace": "{pwd}/data/user_workspaces/admin", - "Locale": "zh_CN", + "Locale": "en_US", "GoFormat": "gofmt", "LatestSessionContent": { "FileTree": [], diff --git a/data/user_workspaces/admin/src/gotest/example1_test.go b/data/user_workspaces/admin/src/gotest/example1_test.go new file mode 100644 index 0000000..8c9c857 --- /dev/null +++ b/data/user_workspaces/admin/src/gotest/example1_test.go @@ -0,0 +1,16 @@ +package test + +import ( + "testing" +) + +func Test_Division_1(t *testing.T) { + if i, e := Division(6, 2); i != 3 || e != nil { //try a unit test on function + t.Error("除法函数测试没通过") // 如果不是如预期的那么就报错 + } else { + t.Log("第一个测试通过了") //记录一些你期望记录的信息 + } +} + +func Test_Division_2(t *testing.T) { +} diff --git a/data/user_workspaces/admin/src/gotest/example2_test.go b/data/user_workspaces/admin/src/gotest/example2_test.go new file mode 100644 index 0000000..ebdfe2b --- /dev/null +++ b/data/user_workspaces/admin/src/gotest/example2_test.go @@ -0,0 +1,17 @@ +package test + +import ( + "testing" +) + +func Test_Division_3(t *testing.T) { + if i, e := Division(6, 2); i != 3 || e != nil { //try a unit test on function + t.Error("除法函数测试没通过") // 如果不是如预期的那么就报错 + } else { + t.Log("第一个测试通过了") //记录一些你期望记录的信息 + } +} + +func Test_Division_4(t *testing.T) { + t.Error("就是不通过") +} diff --git a/data/user_workspaces/admin/src/gotest/test.go b/data/user_workspaces/admin/src/gotest/test.go new file mode 100644 index 0000000..8394003 --- /dev/null +++ b/data/user_workspaces/admin/src/gotest/test.go @@ -0,0 +1,13 @@ +package test + +import ( + "errors" +) + +func Division(a, b float64) (float64, error) { + if b == 0 { + return 0, errors.New("除数不能为0") + } + + return a / b, nil +} diff --git a/data/user_workspaces/admin/src/mytest/hello/main.go b/data/user_workspaces/admin/src/hello/main.go similarity index 100% rename from data/user_workspaces/admin/src/mytest/hello/main.go rename to data/user_workspaces/admin/src/hello/main.go diff --git a/data/user_workspaces/admin/src/mytest/time/index.html b/data/user_workspaces/admin/src/mytest/time/index.html deleted file mode 100644 index 3d0944b..0000000 --- a/data/user_workspaces/admin/src/mytest/time/index.html +++ /dev/null @@ -1,411 +0,0 @@ - - - - - - {{.i18n.wide}} - - - - - - - - - - - - - - - - - - -
-
- - -
-
- - {{.i18n.file}} - - -
-
-
-
-
    -
- -
-
    -
  • - {{.i18n.create_file}} - -
  • -
  • - {{.i18n.create_dir}} - -
  • -
  • - {{.i18n.delete}} - -
  • -
-
- -
-
    -
  • - {{.i18n.delete}} - -
  • -
-
-
-
-
-
-
- - - - - - - - -
-
-
-
-
-
-
- - -
-
- - {{.i18n.output}} - - -
-
- - {{.i18n.search}} - - -
-
- - {{.i18n.notification}} - - -
-
-
-
- -
-
- -
-
-
- -
-
-
-
-
-
- -
- {{.i18n.isDelete}} - - - - ? - -
-
-
-
- -
-
- -
-
- -
-
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/data/user_workspaces/admin/src/mytest/time/main.go b/data/user_workspaces/admin/src/time/main.go similarity index 89% rename from data/user_workspaces/admin/src/mytest/time/main.go rename to data/user_workspaces/admin/src/time/main.go index 5cb2f19..a95a3fd 100644 --- a/data/user_workspaces/admin/src/mytest/time/main.go +++ b/data/user_workspaces/admin/src/time/main.go @@ -2,8 +2,8 @@ package main import ( "fmt" - "mytest/time/pkg" "time" + "time/pkg" ) func main() { diff --git a/data/user_workspaces/admin/src/mytest/time/pkg/time.go b/data/user_workspaces/admin/src/time/pkg/time.go similarity index 100% rename from data/user_workspaces/admin/src/mytest/time/pkg/time.go rename to data/user_workspaces/admin/src/time/pkg/time.go diff --git a/i18n/en_US.json b/i18n/en_US.json index bac7c64..e1083c9 100644 --- a/i18n/en_US.json +++ b/i18n/en_US.json @@ -7,7 +7,7 @@ "username": "Username", "current_user": "Current User", "password": "Password", - "login_failed": "Login Failed", + "login_error": "Login Error", "run": "Run", "debug": "Debug", "help": "Help", @@ -86,13 +86,16 @@ "focus_notification": "Focus to Notification", "start-build": "START [go build]", "build-succ": "[go build] SUCCESS", - "build-failed": "[go build] Failed", + "build-error": "[go build] ERROR", + "start-test": "START [go test]", + "test-succ": "[go test] SUCCESS", + "test-error": "[go test] ERROR", "start-install": "START [go install]", "install-succ": "[go install] SUCCESS", - "install-failed": "[go install] Fialed", + "install-error": "[go install] ERROR", "start-get": "START [go get]", "get-succ": "[go get] SUCCESS", - "get-failed": "[go get] Failed", + "get-error": "[go get] ERROR", "check_version": "Checking update", "new_version_available": "new version available", "go_env": "Go", @@ -101,5 +104,6 @@ "license": "License", "credits": "Credits", "uptodate": "it is up to date", + "test": "Test", "colon": ": " } \ No newline at end of file diff --git a/i18n/zh_CN.json b/i18n/zh_CN.json index e66384d..0e3a466 100644 --- a/i18n/zh_CN.json +++ b/i18n/zh_CN.json @@ -7,7 +7,7 @@ "username": "用户名", "current_user": "当前用户", "password": "密码", - "login_failed": "登录失败", + "login_error": "登录失败", "run": "运行", "debug": "调试", "help": "帮助", @@ -86,13 +86,16 @@ "focus_notification": "焦点切换到通知窗口", "start-build": "开始 [go build]", "build-succ": "[go build] 成功", - "build-failed": "[go build] 失败", + "build-error": "[go build] 失败", + "start-test": "开始 [go test]", + "test-succ": "[go test] 成功", + "test-error": "[go test] 失败", "start-install": "开始 [go install]", "install-succ": "[go install] 成功", - "install-failed": "[go install] 失败", + "install-error": "[go install] 失败", "start-get": "开始 [go get]", "get-succ": "[go get] 成功", - "get-failed": "[go get] 失败", + "get-error": "[go get] 失败", "check_version": "正在检查更新", "new_version_available": "新版本可用", "go_env": "Go 环境", @@ -101,5 +104,6 @@ "license": "许可协议", "credits": "致谢", "uptodate": "已是最新版本", + "test": "测试", "colon": ":" } \ No newline at end of file diff --git a/main.go b/main.go index c526665..e8f344a 100644 --- a/main.go +++ b/main.go @@ -294,6 +294,7 @@ func main() { http.HandleFunc("/build", handlerWrapper(output.BuildHandler)) http.HandleFunc("/run", handlerWrapper(output.RunHandler)) http.HandleFunc("/stop", handlerWrapper(output.StopHandler)) + http.HandleFunc("/go/test", handlerWrapper(output.GoTestHandler)) http.HandleFunc("/go/get", handlerWrapper(output.GoGetHandler)) http.HandleFunc("/go/install", handlerWrapper(output.GoInstallHandler)) http.HandleFunc("/output/ws", handlerWrapper(output.WSHandler)) diff --git a/output/outputs.go b/output/outputs.go index c1038ed..e238d92 100644 --- a/output/outputs.go +++ b/output/outputs.go @@ -56,11 +56,9 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { data := map[string]interface{}{"succ": true} defer util.RetJSON(w, r, data) - decoder := json.NewDecoder(r.Body) - var args map[string]interface{} - if err := decoder.Decode(&args); err != nil { + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { glog.Error(err) data["succ"] = false @@ -188,11 +186,9 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) { username := httpSession.Values["username"].(string) locale := conf.Wide.GetUser(username).Locale - decoder := json.NewDecoder(r.Body) - var args map[string]interface{} - if err := decoder.Decode(&args); err != nil { + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { glog.Error(err) data["succ"] = false @@ -330,7 +326,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) { } else { // 构建失败 // 解析错误信息,返回给编辑器 gutter lint errOut := string(buf) - channelRet["output"] = "" + i18n.Get(locale, "build-failed").(string) + "\n" + errOut + channelRet["output"] = "" + i18n.Get(locale, "build-error").(string) + "\n" + errOut lines := strings.Split(errOut, "\n") @@ -390,8 +386,8 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) { }(rand.Int()) } -// go install. -func GoInstallHandler(w http.ResponseWriter, r *http.Request) { +// go test. +func GoTestHandler(w http.ResponseWriter, r *http.Request) { data := map[string]interface{}{"succ": true} defer util.RetJSON(w, r, data) @@ -399,11 +395,9 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) { username := httpSession.Values["username"].(string) locale := conf.Wide.GetUser(username).Locale - decoder := json.NewDecoder(r.Body) - var args map[string]interface{} - if err := decoder.Decode(&args); err != nil { + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { glog.Error(err) data["succ"] = false @@ -415,8 +409,12 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) { filePath := args["file"].(string) curDir := filePath[:strings.LastIndex(filePath, conf.PathSeparator)] - fout, err := os.Create(filePath) + cmd := exec.Command("go", "test", "-v") + cmd.Dir = curDir + setCmdEnv(cmd, username) + + stdout, err := cmd.StdoutPipe() if nil != err { glog.Error(err) data["succ"] = false @@ -424,17 +422,108 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) { return } - code := args["code"].(string) - - fout.WriteString(code) - - if err := fout.Close(); nil != err { + stderr, err := cmd.StderrPipe() + if nil != err { glog.Error(err) data["succ"] = false return } + if !data["succ"].(bool) { + return + } + + channelRet := map[string]interface{}{} + + if nil != session.OutputWS[sid] { + // 在前端 output 中显示“开始 go test + + channelRet["output"] = "" + i18n.Get(locale, "start-test").(string) + "\n" + channelRet["cmd"] = "start-test" + + wsChannel := session.OutputWS[sid] + + err := wsChannel.Conn.WriteJSON(&channelRet) + if nil != err { + glog.Error(err) + return + } + + // 更新通道最近使用时间 + wsChannel.Time = time.Now() + } + + reader := bufio.NewReader(io.MultiReader(stdout, stderr)) + + if err := cmd.Start(); nil != err { + glog.Error(err) + data["succ"] = false + + return + } + + go func(runningId int) { + defer util.Recover() + + glog.V(3).Infof("Session [%s] is running [go test] [runningId=%d]", sid, runningId) + + channelRet := map[string]interface{}{} + channelRet["cmd"] = "go test" + + // 一次性读取 + buf, _ := ioutil.ReadAll(reader) + + // 同步点,等待 go test 执行完成 + cmd.Wait() + + if !cmd.ProcessState.Success() { + glog.V(3).Infof("Session [%s] 's running [go test] [runningId=%d] has done (with error)", sid, runningId) + + channelRet["output"] = "" + i18n.Get(locale, "test-error").(string) + "\n" + string(buf) + } else { + glog.V(3).Infof("Session [%s] 's running [go test] [runningId=%d] has done", sid, runningId) + + channelRet["output"] = "" + i18n.Get(locale, "test-succ").(string) + "\n" + string(buf) + } + + if nil != session.OutputWS[sid] { + wsChannel := session.OutputWS[sid] + + err := wsChannel.Conn.WriteJSON(&channelRet) + if nil != err { + glog.Error(err) + } + + // 更新通道最近使用时间 + wsChannel.Time = time.Now() + } + }(rand.Int()) +} + +// go install. +func GoInstallHandler(w http.ResponseWriter, r *http.Request) { + data := map[string]interface{}{"succ": true} + defer util.RetJSON(w, r, data) + + httpSession, _ := session.HTTPSession.Get(r, "wide-session") + username := httpSession.Values["username"].(string) + locale := conf.Wide.GetUser(username).Locale + + var args map[string]interface{} + + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { + glog.Error(err) + data["succ"] = false + + return + } + + sid := args["sid"].(string) + + filePath := args["file"].(string) + curDir := filePath[:strings.LastIndex(filePath, conf.PathSeparator)] + cmd := exec.Command("go", "install") cmd.Dir = curDir @@ -547,7 +636,7 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) { channelRet["lints"] = lints - channelRet["output"] = "" + i18n.Get(locale, "install-failed").(string) + "\n" + errOut + channelRet["output"] = "" + i18n.Get(locale, "install-error").(string) + "\n" + errOut } else { channelRet["output"] = "" + i18n.Get(locale, "install-succ").(string) + "\n" } @@ -577,11 +666,9 @@ func GoGetHandler(w http.ResponseWriter, r *http.Request) { username := httpSession.Values["username"].(string) locale := conf.Wide.GetUser(username).Locale - decoder := json.NewDecoder(r.Body) - var args map[string]interface{} - if err := decoder.Decode(&args); err != nil { + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { glog.Error(err) data["succ"] = false @@ -662,7 +749,7 @@ func GoGetHandler(w http.ResponseWriter, r *http.Request) { if 0 != len(buf) { glog.V(3).Infof("Session [%s] 's running [go get] [runningId=%d] has done (with error)", sid, runningId) - channelRet["output"] = "" + i18n.Get(locale, "get-failed").(string) + "\n" + string(buf) + channelRet["output"] = "" + i18n.Get(locale, "get-error").(string) + "\n" + string(buf) } else { glog.V(3).Infof("Session [%s] 's running [go get] [runningId=%d] has done", sid, runningId) diff --git a/static/css/wide.css b/static/css/wide.css index d7eb7c8..5d8f89b 100644 --- a/static/css/wide.css +++ b/static/css/wide.css @@ -271,6 +271,7 @@ } .bottom-window-group .output { + font-family: Consolas, Courier New, monospace; padding: 0 5px; line-height: 16px; font-size: 12px; @@ -281,20 +282,23 @@ } .bottom-window-group .output .start-build, +.bottom-window-group .output .start-test, .bottom-window-group .output .start-install, .bottom-window-group .output .start-get { color: #999; } -.bottom-window-group .output .build-succ, +.bottom-window-group .output .build-succ, +.bottom-window-group .output .test-succ, .bottom-window-group .output .install-succ, .bottom-window-group .output .get-succ { color: rgb(0,153,0); } -.bottom-window-group .output .build-failed, -.bottom-window-group .output .install-failed, -.bottom-window-group .output .get-failed { +.bottom-window-group .output .build-error, +.bottom-window-group .output .test-error, +.bottom-window-group .output .install-error, +.bottom-window-group .output .get-error { color: red; } diff --git a/static/js/editors.js b/static/js/editors.js index 031b577..d2e13a0 100644 --- a/static/js/editors.js +++ b/static/js/editors.js @@ -24,7 +24,7 @@ var editors = { wide.curEditor.focus(); }, removeAfter: function (id, nextId) { - if (id === 'startPage') { + if (id === 'startPage') { // 当前关闭的 tab 是起始页 return false; } @@ -35,6 +35,10 @@ var editors = { break; } } + if (editors.data.length === 0) { // 起始页可能存在,所以用编辑器数据判断 + menu.disabled(['save-all', 'close-all', 'build', 'run', 'go-test', 'go-get', 'go-install']); + $(".toolbars").hide(); + } if (!nextId) { // 不存在打开的编辑器 @@ -43,9 +47,6 @@ var editors = { wide.curNode = undefined; wide.curEditor = undefined; - - menu.disabled(['save-all', 'close-all', 'run', 'go-get', 'go-install']); - $(".toolbars").hide(); return false; } @@ -440,7 +441,7 @@ var editors = { content: '' }); - menu.undisabled(['save-all', 'close-all', 'run', 'go-get', 'go-install']); + menu.undisabled(['save-all', 'close-all', 'build', 'run', 'go-test', 'go-get', 'go-install']); var rulers = []; rulers.push({color: "#ccc", column: 120, lineStyle: "dashed"}); diff --git a/static/js/wide.js b/static/js/wide.js index f4a3d48..751174b 100644 --- a/static/js/wide.js +++ b/static/js/wide.js @@ -351,11 +351,13 @@ var wide = { break; case 'start-build': + case 'start-test': case 'start-install': case 'start-get': wide.fillOutput(data.output); break; + case 'go test': case 'go install': case 'go get': wide.fillOutput($('.bottom-window-group .output > div').html() + data.output); @@ -541,6 +543,10 @@ var wide = { if (!currentPath) { return false; } + + if ($(".menu li.build").hasClass("disabled")) { + return false; + } var request = newWideRequest(); request.file = currentPath; @@ -600,6 +606,36 @@ var wide = { } }); }, + // 测试. + test: function () { + wide.saveAllFiles(); + + var currentPath = editors.getCurrentPath(); + if (!currentPath) { + return false; + } + + if ($(".menu li.test").hasClass("disabled")) { + return false; + } + + var request = newWideRequest(); + request.file = currentPath; + + $.ajax({ + type: 'POST', + url: '/go/test', + data: JSON.stringify(request), + dataType: "json", + beforeSend: function (data) { + $('.bottom-window-group .output > div').text(''); + wide.bottomWindowTab.setCurrent("output"); + windows.flowBottom(); + }, + success: function (data) { + } + }); + }, goget: function () { wide.saveAllFiles(); @@ -643,7 +679,6 @@ var wide = { var request = newWideRequest(); request.file = currentPath; - request.code = wide.curEditor.getValue(); $.ajax({ type: 'POST', diff --git a/views/index.html b/views/index.html index b49e5f1..597c2e4 100644 --- a/views/index.html +++ b/views/index.html @@ -46,13 +46,17 @@ {{.i18n.run}}