Merge pull request #98 from b3log/1.1.0

1.1.0
This commit is contained in:
Liang Ding 2014-10-26 18:29:50 +08:00
commit 7fc41ca5fb
10 changed files with 138 additions and 76 deletions

View File

@ -36,6 +36,7 @@ type User struct {
Password string
Workspace string // 该用户的工作空间 GOPATH 路径
Locale string
GoFormat string
LatestSessionContent *LatestSessionContent
}
@ -83,7 +84,7 @@ func FixedTimeCheckEnv() {
os.Exit(-1)
}
gocode := Wide.GetGocode()
gocode := Wide.GetExecutableInGOBIN("gocode")
cmd := exec.Command(gocode, "close")
_, err := cmd.Output()
if nil != err {
@ -91,7 +92,7 @@ func FixedTimeCheckEnv() {
glog.Warningf("Not found gocode [%s]", gocode)
}
ide_stub := Wide.GetIDEStub()
ide_stub := Wide.GetExecutableInGOBIN("ide_stub")
cmd = exec.Command(ide_stub, "version")
_, err = cmd.Output()
if nil != err {
@ -131,11 +132,23 @@ func (c *conf) GetWorkspace() string {
return filepath.FromSlash(strings.Replace(c.Workspace, "{pwd}", c.Pwd, 1))
}
// 获取 user 的工作空间路径.
func (user *User) getWorkspace() string {
ret := strings.Replace(user.Workspace, "{pwd}", Wide.Pwd, 1)
// 获取 username 指定的用户的 Go 源码格式化工具路径,查找不到时返回 "gofmt".
func (c *conf) GetGoFmt(username string) string {
for _, user := range c.Users {
if user.Name == username {
switch user.GoFormat {
case "gofmt":
return "gofmt"
case "goimports":
return c.GetExecutableInGOBIN("goimports")
default:
glog.Errorf("Unsupported Go Format tool [%s]", user.GoFormat)
return "gofmt"
}
}
}
return filepath.FromSlash(ret)
return "gofmt"
}
// 获取 username 指定的用户配置.
@ -149,40 +162,40 @@ func (*conf) GetUser(username string) *User {
return nil
}
// 获取 gocode 路径.
func (*conf) GetGocode() string {
return getGOBIN() + "gocode"
}
// 获取 ide_stub 路径.
func (*conf) GetIDEStub() string {
return getGOBIN() + "ide_stub"
}
// 获取 GOBIN 路径,末尾带路径分隔符.
func getGOBIN() string {
// $GOBIN/
ret := os.Getenv("GOBIN")
if "" != ret {
return ret + PathSeparator
// 获取 GOBIN 中 executable 指定的文件路径.
//
// 函数内部会判断操作系统,如果是 Windows 则在 executable 实参后加入 .exe 后缀.
func (*conf) GetExecutableInGOBIN(executable string) string {
if util.OS.IsWindows() {
executable += ".exe"
}
// $GOPATH/bin/$GOOS_$GOARCH/
ret = os.Getenv("GOPATH") + PathSeparator + "bin" + PathSeparator +
os.Getenv("GOOS") + "_" + os.Getenv("GOARCH")
if isExist(ret) {
return ret + PathSeparator
gopaths := strings.Split(os.Getenv("GOPATH"), PathListSeparator)
for _, gopath := range gopaths {
// $GOPATH/bin/$GOOS_$GOARCH/executable
ret := gopath + PathSeparator + "bin" + PathSeparator +
os.Getenv("GOOS") + "_" + os.Getenv("GOARCH") + PathSeparator + executable
if isExist(ret) {
return ret
}
// $GOPATH/bin/{runtime.GOOS}_{runtime.GOARCH}/executable
ret = gopath + PathSeparator + "bin" + PathSeparator +
runtime.GOOS + "_" + runtime.GOARCH + PathSeparator + executable
if isExist(ret) {
return ret
}
// $GOPATH/bin/executable
ret = gopath + PathSeparator + "bin" + PathSeparator + executable
if isExist(ret) {
return ret
}
}
// $GOPATH/bin/{runtime.GOOS}_{runtime.GOARCH}/
ret = os.Getenv("GOPATH") + PathSeparator + "bin" + PathSeparator +
runtime.GOOS + "_" + runtime.GOARCH
if isExist(ret) {
return ret + PathSeparator
}
// $GOPATH/bin/
return os.Getenv("GOPATH") + PathSeparator + "bin" + PathSeparator
// $GOBIN/executable
return os.Getenv("GOBIN") + PathSeparator + executable
}
// 保存 Wide 配置.

View File

@ -18,6 +18,7 @@
"Password": "admin",
"Workspace": "{pwd}/data/user_workspaces/admin",
"Locale": "zh_CN",
"GoFormat": "gofmt",
"LatestSessionContent": {
"FileTree": [],
"Files": [],

View File

@ -56,7 +56,7 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
// glog.Infof("offset: %d", offset)
gocode := conf.Wide.GetGocode()
gocode := conf.Wide.GetExecutableInGOBIN("gocode")
argv := []string{"-f=json", "autocomplete", strconv.Itoa(offset)}
var output bytes.Buffer
@ -124,16 +124,18 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
// glog.Infof("offset: %d", offset)
userWorkspace := conf.Wide.GetUserWorkspace(username)
workspaces := strings.Split(userWorkspace, conf.PathListSeparator)
libPath := ""
for _, workspace := range workspaces {
userLib := workspace + conf.PathSeparator + "pkg" + conf.PathSeparator +
runtime.GOOS + "_" + runtime.GOARCH
libPath += userLib + conf.PathListSeparator
}
//glog.Infof("User [%s] workspace [%s]", username, userWorkspace)
userLib := userWorkspace + conf.PathSeparator + "pkg" + conf.PathSeparator +
runtime.GOOS + "_" + runtime.GOARCH
libPath := userLib
//glog.Infof("gocode set lib-path %s", libPath)
glog.V(5).Infof("gocode set lib-path %s", libPath)
// FIXME: 使用 gocode set lib-path 在多工作空间环境下肯定是有问题的,需要考虑其他实现方式
gocode := conf.Wide.GetGocode()
gocode := conf.Wide.GetExecutableInGOBIN("gocode")
argv := []string{"set", "lib-path", libPath}
exec.Command(gocode, argv...).Run()
@ -205,7 +207,7 @@ func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
// glog.Infof("offset [%d]", offset)
// TODO: 目前是调用 liteide_stub 工具来查找声明,后续需要重新实现
ide_stub := conf.Wide.GetIDEStub()
ide_stub := conf.Wide.GetExecutableInGOBIN("ide_stub")
argv := []string{"type", "-cursor", filename + ":" + strconv.Itoa(offset), "-info", "."}
cmd := exec.Command(ide_stub, argv...)
cmd.Dir = curDir
@ -279,7 +281,7 @@ func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
// glog.Infof("offset [%d]", offset)
// TODO: 目前是调用 liteide_stub 工具来查找声明,后续需要重新实现
ide_stub := conf.Wide.GetIDEStub()
ide_stub := conf.Wide.GetExecutableInGOBIN("ide_stub")
argv := []string{"type", "-cursor", filename + ":" + strconv.Itoa(offset), "-def", "."}
cmd := exec.Command(ide_stub, argv...)
cmd.Dir = curDir
@ -361,7 +363,7 @@ func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
// glog.Infof("offset [%d]", offset)
// TODO: 目前是调用 liteide_stub 工具来查找使用,后续需要重新实现
ide_stub := conf.Wide.GetIDEStub()
ide_stub := conf.Wide.GetExecutableInGOBIN("ide_stub")
argv := []string{"type", "-cursor", filename + ":" + strconv.Itoa(offset), "-use", "."}
cmd := exec.Command(ide_stub, argv...)
cmd.Dir = curDir

View File

@ -5,24 +5,30 @@ import (
"net/http"
"os"
"os/exec"
"runtime"
"strings"
"github.com/88250/gohtml"
"github.com/b3log/wide/conf"
"github.com/b3log/wide/session"
"github.com/b3log/wide/util"
"github.com/golang/glog"
)
// TODO: 加入 goimports 格式化 Go 源码文件
// gofmt 格式化 Go 源码文件.
// 格式化 Go 源码文件.
// 根据用户的 GoFormat 配置选择格式化工具:
// 1. gofmt
// 2. goimports
func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data)
decoder := json.NewDecoder(r.Body)
session, _ := session.HTTPSession.Get(r, "wide-session")
username := session.Values["username"].(string)
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
@ -31,6 +37,12 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
filePath := args["file"].(string)
apiPath := runtime.GOROOT() + conf.PathSeparator + "src" + conf.PathSeparator + "pkg"
if strings.HasPrefix(filePath, apiPath) { // 如果是 Go API 源码文件
// 忽略修改
return
}
fout, err := os.Create(filePath)
if nil != err {
@ -50,8 +62,10 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
return
}
fmt := conf.Wide.GetGoFmt(username)
argv := []string{filePath}
cmd := exec.Command("gofmt", argv...)
cmd := exec.Command(fmt, argv...)
bytes, _ := cmd.Output()
output := string(bytes)

View File

@ -45,9 +45,24 @@ func GetFiles(w http.ResponseWriter, r *http.Request) {
session, _ := session.HTTPSession.Get(r, "wide-session")
username := session.Values["username"].(string)
userSrc := conf.Wide.GetUserWorkspace(username) + conf.PathSeparator + "src"
userWorkspace := conf.Wide.GetUserWorkspace(username)
workspaces := strings.Split(userWorkspace, conf.PathListSeparator)
root := FileNode{Name: "projects", Path: userSrc, IconSkin: "ico-ztree-dir ", Type: "d", FileNodes: []*FileNode{}}
root := FileNode{Name: "root", Path: "", IconSkin: "ico-ztree-dir ", Type: "d", FileNodes: []*FileNode{}}
// 工作空间节点处理
for _, workspace := range workspaces {
workspacePath := workspace + conf.PathSeparator + "src"
workspaceNode := FileNode{Name: workspace[strings.LastIndex(workspace, conf.PathSeparator)+1:] + " (" +
workspace + ")",
Path: workspacePath, IconSkin: "ico-ztree-dir ", Type: "d", FileNodes: []*FileNode{}}
walk(workspacePath, &workspaceNode)
// 添加工作空间节点
root.FileNodes = append(root.FileNodes, &workspaceNode)
}
// 构造 Go API 节点
apiPath := runtime.GOROOT() + conf.PathSeparator + "src" + conf.PathSeparator + "pkg"
@ -65,9 +80,6 @@ func GetFiles(w http.ResponseWriter, r *http.Request) {
close(goapiBuildOKSignal)
}()
// 构造用户工作空间文件树
walk(userSrc, &root)
// 等待放行
<-goapiBuildOKSignal
@ -381,28 +393,30 @@ func createFile(path, fileType string) bool {
case "f":
file, err := os.OpenFile(path, os.O_CREATE, 0664)
if nil != err {
glog.Info(err)
glog.Error(err)
return false
}
defer file.Close()
glog.Infof("Created file [%s]", path)
glog.V(5).Infof("Created file [%s]", path)
return true
case "d":
err := os.Mkdir(path, 0775)
if nil != err {
glog.Info(err)
glog.Error(err)
return false
}
glog.Infof("Created directory [%s]", path)
glog.V(5).Infof("Created directory [%s]", path)
return true
default:
glog.Infof("Unsupported file type [%s]", fileType)
glog.Errorf("Unsupported file type [%s]", fileType)
return false
}

21
main.go
View File

@ -53,8 +53,6 @@ func init() {
// 登录.
func loginHandler(w http.ResponseWriter, r *http.Request) {
i18n.Load()
if "GET" == r.Method {
// 展示登录页面
@ -126,8 +124,6 @@ func logoutHandler(w http.ResponseWriter, r *http.Request) {
// Wide 首页.
func indexHandler(w http.ResponseWriter, r *http.Request) {
i18n.Load()
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
if httpSession.IsNew {
@ -175,8 +171,6 @@ func serveSingle(pattern string, filename string) {
// 起始页请求处理.
func startHandler(w http.ResponseWriter, r *http.Request) {
i18n.Load()
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
if httpSession.IsNew {
@ -209,8 +203,6 @@ func startHandler(w http.ResponseWriter, r *http.Request) {
// 键盘快捷键页请求处理.
func keyboardShortcutsHandler(w http.ResponseWriter, r *http.Request) {
i18n.Load()
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
if httpSession.IsNew {
@ -241,8 +233,6 @@ func keyboardShortcutsHandler(w http.ResponseWriter, r *http.Request) {
// 关于页请求处理.
func aboutHandler(w http.ResponseWriter, r *http.Request) {
i18n.Load()
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
if httpSession.IsNew {
@ -356,10 +346,21 @@ func main() {
func handlerWrapper(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
handler := panicRecover(f)
handler = stopwatch(handler)
handler = i18nLoad(handler)
return handler
}
// 国际化处理包装.
func i18nLoad(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
i18n.Load()
// Handler 处理
handler(w, r)
}
}
// Handler 包装请求计时.
func stopwatch(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {

View File

@ -225,7 +225,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
}
suffix := ""
if "windows" == runtime.GOOS {
if util.OS.IsWindows() {
suffix = ".exe"
}
executable := "main" + suffix

View File

@ -25,8 +25,6 @@ var ShellWS = map[string]*util.WSChannel{}
// Shell 首页.
func IndexHandler(w http.ResponseWriter, r *http.Request) {
i18n.Load()
httpSession, _ := session.HTTPSession.Get(r, "wide-session")
if httpSession.IsNew {

View File

@ -509,6 +509,10 @@ var wide = {
wide.run();
return false;
}
if (!wide.curProcessId) {
return false;
}
var request = newWideRequest();
request.pid = wide.curProcessId;

15
util/os.go Normal file
View File

@ -0,0 +1,15 @@
package util
import (
"runtime"
)
type myos struct{}
// 操作系统工具.
var OS = myos{}
// 判断是否是 Windows 操作系统.
func (*myos) IsWindows() bool {
return "windows" == runtime.GOOS
}