Compare commits
97 Commits
Author | SHA1 | Date |
---|---|---|
|
c3c3031f37 | |
|
a7b9baaaaf | |
|
593d9241be | |
|
35ac5a50d6 | |
|
f6a72ff464 | |
|
24d4654030 | |
|
58611c8f1e | |
|
9076912b9d | |
|
68fee17793 | |
|
877e96df4d | |
|
029982f00e | |
|
5cfb9ca5fb | |
|
93654cfa32 | |
|
de0110eadf | |
|
2e53a02446 | |
|
3a4aabc297 | |
|
9b8c3eb888 | |
|
7f9f726f71 | |
|
a0ec5a70b7 | |
|
51a3f6b932 | |
|
791f438ff9 | |
|
e3c3b165c8 | |
|
3256f60990 | |
|
e51b78ea85 | |
|
3bf430e35f | |
|
12c5da94f6 | |
|
cd9d0165c0 | |
|
231a35c725 | |
|
dbd41730ae | |
|
c84ead6140 | |
|
786a0f5c4a | |
|
624ef3a152 | |
|
1287018811 | |
|
3193610b7f | |
|
c065239e69 | |
|
7d222f22cb | |
|
ab4feaba81 | |
|
aa65a8db04 | |
|
e4f0e410b8 | |
|
0568356fdc | |
|
215820f02b | |
|
c3b7c26119 | |
|
89e3b7be8f | |
|
358067ea10 | |
|
bd54c4ef10 | |
|
47374dd8c8 | |
|
e84f994f2b | |
|
90303f2aed | |
|
f633ca07eb | |
|
a6f9de5a62 | |
|
d26f35bc5f | |
|
5f0612530a | |
|
e281d0f554 | |
|
dd949ae6a3 | |
|
6d8a334131 | |
|
3cf3063e76 | |
|
fbb824de6e | |
|
ef52c48b26 | |
|
1c295785d0 | |
|
b57889bdac | |
|
9d0113f979 | |
|
7a254f89d8 | |
|
544cb886ec | |
|
cdc1f5408b | |
|
f6bdc5f176 | |
|
d3ab996830 | |
|
bae3ad8c20 | |
|
7dafee49e9 | |
|
efce7adc51 | |
|
d474e913f6 | |
|
c5fdd3f0a6 | |
|
6dc68d4aa5 | |
|
c0c00bf9c8 | |
|
4f9221c313 | |
|
f3e9502443 | |
|
00439ae418 | |
|
c931e611db | |
|
b53d2d28b7 | |
|
83d52b107a | |
|
4930408b17 | |
|
1405d7482a | |
|
0253ad8e45 | |
|
4da07183a9 | |
|
1eb2a78c3b | |
|
6bd4efd16f | |
|
17e59cf55a | |
|
879b3d78c3 | |
|
ce8351f38c | |
|
58ae60da85 | |
|
5c549a56c5 | |
|
38f88c2c17 | |
|
1857df995d | |
|
67c36e0089 | |
|
d764f13192 | |
|
9716c3027f | |
|
e2c0b8ec8a | |
|
2e0f150cdb |
|
@ -1 +1,3 @@
|
|||
static/js/lib/* linguist-vendored
|
||||
static/js/overwrite/* linguist-vendored
|
||||
*.min.js linguist-vendored
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
---
|
||||
name: 报告缺陷
|
||||
about: 报告缺陷以帮助我们改进
|
||||
---
|
||||
|
||||
**请先看[《提问的智慧》](https://hacpai.com/article/1536377163156)**,并尝试到[讨论区](https://hacpai.com/tag/wide)搜寻资料解决问题。
|
||||
|
||||
----
|
||||
|
||||
### 描述问题
|
||||
|
||||
请尽量清晰精准地描述你碰到的问题。
|
||||
|
||||
### 重现步骤
|
||||
|
||||
请描述如何重现这个问题:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See error
|
||||
|
||||
### 期待的结果
|
||||
|
||||
请尽量清晰精准地描述你所期待的结果。
|
||||
|
||||
### 截屏或录像
|
||||
|
||||
如果可能,请尽量附加截图或录像来描述你遇到的问题。
|
||||
|
||||
### 桌面端环境
|
||||
|
||||
- OS: [e.g. windows, mac, linux]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
### 移动端环境
|
||||
|
||||
- Device: [e.g. iPhone8]
|
||||
- OS: [e.g. iOS12]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
### 其他信息
|
||||
|
||||
请提供其他附加信息帮助我们诊断问题。
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
name: 请求新功能
|
||||
about: 提出你期待的功能特性
|
||||
---
|
||||
|
||||
### 你在什么场景下需要该功能?
|
||||
|
||||
请尽量清晰精准地描述你碰到的问题。
|
||||
|
||||
### 描述可能的解决方案
|
||||
|
||||
请尽量清晰精准地描述你期待我们要做的,描述你想到的实现方案。
|
||||
|
||||
### 描述你认为的候选方案
|
||||
|
||||
请尽量清晰精准地描述你能接受的候选解决方案。
|
||||
|
||||
### 其他信息
|
||||
|
||||
请提供关于该功能建议的其他附加信息。
|
|
@ -2,10 +2,3 @@ language: go
|
|||
|
||||
go:
|
||||
- 1.12
|
||||
before_install:
|
||||
- go get github.com/axw/gocov/gocov
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- ./coverage.sh
|
||||
- $HOME/gopath/bin/goveralls -coverprofile=profile.cov -service=travis-ci -repotoken W04Y4p452CDeI9gcsC8t5y217uHnUDFCb
|
||||
|
|
146
README.md
146
README.md
|
@ -1,160 +1,18 @@
|
|||
<p align = "center">
|
||||
<img alt="Wide" src="https://user-images.githubusercontent.com/873584/57901570-5355ba00-7898-11e9-96ca-45b75b1d70db.png">
|
||||
<br><br>
|
||||
一款基于 Web 的 Go 语言 IDE
|
||||
<br><br>
|
||||
<a title="Build Status" target="_blank" href="https://travis-ci.org/b3log/wide"><img src="https://img.shields.io/travis/b3log/wide.svg?style=flat-square"></a>
|
||||
<a title="Go Report Card" target="_blank" href="https://goreportcard.com/report/github.com/b3log/wide"><img src="https://goreportcard.com/badge/github.com/b3log/wide?style=flat-square"></a>
|
||||
<a title="Coverage Status" target="_blank" href="https://coveralls.io/repos/github/b3log/wide/badge.svg?branch=master"><img src="https://img.shields.io/coveralls/github/b3log/wide.svg?style=flat-square&color=CC9933"></a>
|
||||
<a title="Code Size" target="_blank" href="https://github.com/b3log/wide"><img src="https://img.shields.io/github/languages/code-size/b3log/wide.svg?style=flat-square"></a>
|
||||
<a title="Apache License" target="_blank" href="https://github.com/b3log/wide/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-apache2-orange.svg?style=flat-square"></a>
|
||||
<br>
|
||||
<a title="Releases" target="_blank" href="https://github.com/b3log/wide/releases"><img src="https://img.shields.io/github/release/b3log/wide.svg?style=flat-square"></a>
|
||||
<a title="Release Date" target="_blank" href="https://github.com/b3log/wide/releases"><img src="https://img.shields.io/github/release-date/b3log/wide.svg?style=flat-square&color=99CCFF"></a>
|
||||
<a title="GitHub Commits" target="_blank" href="https://github.com/b3log/wide/commits/master"><img src="https://img.shields.io/github/commit-activity/m/b3log/wide.svg?style=flat-square"></a>
|
||||
<a title="Last Commit" target="_blank" href="https://github.com/b3log/wide/commits/master"><img src="https://img.shields.io/github/last-commit/b3log/wide.svg?style=flat-square&color=FF9900"></a>
|
||||
<a title="GitHub Pull Requests" target="_blank" href="https://github.com/b3log/wide/pulls"><img src="https://img.shields.io/github/issues-pr-closed/b3log/wide.svg?style=flat-square&color=FF9966"></a>
|
||||
<a title="Hits" target="_blank" href="https://github.com/b3log/hits"><img src="https://hits.b3log.org/b3log/wide.svg"></a>
|
||||
<br><br>
|
||||
<a title="GitHub Watchers" target="_blank" href="https://github.com/b3log/wide/watchers"><img src="https://img.shields.io/github/watchers/b3log/wide.svg?label=Watchers&style=social"></a>
|
||||
<a title="GitHub Stars" target="_blank" href="https://github.com/b3log/wide/stargazers"><img src="https://img.shields.io/github/stars/b3log/wide.svg?label=Stars&style=social"></a>
|
||||
<a title="GitHub Forks" target="_blank" href="https://github.com/b3log/wide/network/members"><img src="https://img.shields.io/github/forks/b3log/wide.svg?label=Forks&style=social"></a>
|
||||
<a title="Author GitHub Followers" target="_blank" href="https://github.com/88250"><img src="https://img.shields.io/github/followers/88250.svg?label=Followers&style=social"></a>
|
||||
</p>
|
||||
|
||||
## 简介
|
||||
|
||||
Wide 是一款基于 **W**eb 的 Go 语言 **IDE**。
|
||||
|
||||
## 动机
|
||||
|
||||
目前较为流行的 Go IDE 都有一些缺陷或遗憾:
|
||||
|
||||
* 文本编辑器类(vim/emacs/sublime/Atom 等):对于新手门槛太高,搭建复杂
|
||||
* 插件类(goclipse、IDEA 等):需要原 IDE 支持,不够专业
|
||||
* LiteIDE 界面不够 modern、goland 收费
|
||||
* **缺少网络分享、嵌入网站可运行功能**
|
||||
|
||||
另外,Go IDE 很少,用 Go 本身开发的 IDE 更是没有,这是一次很好的尝试。关于产品定位的讨论请看[这里](https://hacpai.com/article/1438407961481)。
|
||||
|
||||
## 特性
|
||||
|
||||
基于 Web 的 IDE:
|
||||
|
||||
* 只需要浏览器就能进行开发、运行
|
||||
* 跨平台,甚至在移动设备上
|
||||
* 易进行功能扩展
|
||||
* 易与其他系统集成
|
||||
* 极客体验
|
||||
|
||||
核心功能:
|
||||
|
||||
* 代码高亮、折叠:Go/HTML/JavaScript/Markdown 等
|
||||
* 自动完成:Go/HTML 等
|
||||
* 编译检查:编辑器提示编译错误
|
||||
* 格式化:Go/HTML/JSON 等
|
||||
* 运行:支持同时运行多个程序
|
||||
* 代码导航:跳转到声明,查找使用,文件搜索等
|
||||
* Web 开发:前端(HTML/JS/CSS)开发支持
|
||||
* go tool:go mod/install/fmt 等
|
||||
* 项目文件导出
|
||||
* UI/编辑器多主题
|
||||
* 支持交叉编译
|
||||
|
||||
## 界面
|
||||
|
||||
### 主界面
|
||||
* [Wide 用户指南](https://ld246.com/article/1538873544275)
|
||||
* [Wide 开发指南](https://ld246.com/article/1538876422995)
|
||||
|
||||

|
||||
|
||||
### 跳转到文件
|
||||
|
||||

|
||||
|
||||
### 自动完成
|
||||
|
||||

|
||||
|
||||
### 主题
|
||||
|
||||

|
||||
|
||||
### 查看表达式
|
||||
|
||||

|
||||
|
||||
### 构建报错提示
|
||||
|
||||

|
||||
|
||||
### 交叉编译
|
||||
|
||||

|
||||
|
||||
### Playground
|
||||
|
||||

|
||||
|
||||
## 架构
|
||||
|
||||
### 构建与运行
|
||||
|
||||

|
||||
|
||||
* 一个浏览器 tab 对应一个 Wide 会话
|
||||
* 通过 WebSocket 进行程序执行输出推送
|
||||
|
||||
1. 客户端浏览器发送 ````Build```` 请求
|
||||
2. 服务器使用 ````os/exec```` 执行 ````go build```` 命令<br/>
|
||||
2.1. 生成可执行文件
|
||||
3. 客户端浏览器发送 ````Run```` 请求
|
||||
4. 服务器使用 ````os/exec```` 执行文件<br/>
|
||||
4.1. 生成进程<br/>
|
||||
4.2. 运行结果输出到 WebSocket 通道
|
||||
5. 客户端浏览器监听 ````ws.onmessage```` 到消息后做展现
|
||||
|
||||
### 代码辅助
|
||||
|
||||

|
||||
|
||||
* 自动完成
|
||||
* 查找使用
|
||||
|
||||
1. 浏览器客户端发送代码辅助请求
|
||||
2. Handler 根据请求对应的 HTTP 会话获取用户工作空间
|
||||
3. 执行 `gocode`/`ide_stub(gotools)` 命令<br/>
|
||||
3.1 设置环境变量(${GOPATH} 为用户工作空间路径)<br/>
|
||||
3.2 `gocode` 命令需要设置参数 `lib-path`
|
||||
|
||||
## 文档
|
||||
|
||||
* [用户指南](https://hacpai.com/article/1538873544275)
|
||||
* [开发指南](https://hacpai.com/article/1538876422995)
|
||||
|
||||
## 社区
|
||||
|
||||
* [讨论区](https://hacpai.com/tag/wide)
|
||||
* [报告问题](https://github.com/b3log/wide/issues/new/choose)
|
||||
|
||||
## 授权
|
||||
|
||||
Wide 使用 [Apache License, Version 2](https://www.apache.org/licenses/LICENSE-2.0) 作为开源协议,请务必遵循该开源协议相关约定。
|
||||
|
||||
## 鸣谢
|
||||
|
||||
* [golang](https://golang.org)
|
||||
* [CodeMirror](https://github.com/marijnh/CodeMirror)
|
||||
* [zTree](https://github.com/zTree/zTree_v3)
|
||||
* [LiteIDE](https://github.com/visualfc/liteide)
|
||||
* [gocode](https://github.com/nsf/gocode)
|
||||
* [Gorilla](https://github.com/gorilla)
|
||||
* [Docker](https://docker.com)
|
||||
|
||||
----
|
||||
|
||||
## 开源项目推荐
|
||||
|
||||
* 如果你需要搭建一个个人博客系统,可以考虑使用 [Solo](https://github.com/b3log/solo)
|
||||
* 如果你需要搭建一个多用户博客平台,可以考虑使用 [Pipe](https://github.com/b3log/pipe)
|
||||
* 如果你需要搭建一个社区平台,可以考虑使用 [Sym](https://github.com/b3log/symphony)
|
||||
* 欢迎加入我们的小众开源社区,详情请看[这里](https://hacpai.com/article/1463025124998)
|
||||
|
|
|
@ -107,7 +107,7 @@ func NewUser(id, name, avatar, workspace string) *User {
|
|||
|
||||
return &User{Id: id, Name: name, Avatar: avatar, Workspace: workspace,
|
||||
Locale: Wide.Locale, GoFormat: "gofmt",
|
||||
GoBuildArgsForLinux: "-i", GoBuildArgsForWindows: "-i", GoBuildArgsForDarwin: "-i",
|
||||
GoBuildArgsForLinux: "", GoBuildArgsForWindows: "", GoBuildArgsForDarwin: "",
|
||||
FontFamily: "Helvetica", FontSize: "13px", Theme: "default",
|
||||
Keymap: "wide",
|
||||
Created: now, Updated: now, Lived: now,
|
||||
|
|
88
conf/wide.go
88
conf/wide.go
|
@ -17,19 +17,17 @@ package conf
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"html/template"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/event"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/event"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -39,18 +37,18 @@ const (
|
|||
PathListSeparator = string(os.PathListSeparator)
|
||||
|
||||
// WideVersion holds the current Wide's version.
|
||||
WideVersion = "1.5.3"
|
||||
WideVersion = "1.6.0"
|
||||
// CodeMirrorVer holds the current editor version.
|
||||
CodeMirrorVer = "5.1"
|
||||
// UserAgent represents HTTP client user agent.
|
||||
UserAgent = "Wide/" + WideVersion + "; +https://github.com/b3log/wide"
|
||||
UserAgent = "Wide/" + WideVersion + "; +https://github.com/88250/wide"
|
||||
|
||||
HelloWorld = `package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello, 世界")
|
||||
fmt.Println("欢迎通过《边看边练 Go 系列》来学习 Go 语言 https://ld246.com/article/1437497122181")
|
||||
}
|
||||
`
|
||||
)
|
||||
|
@ -65,10 +63,17 @@ type conf struct {
|
|||
StaticResourceVersion string // version of static resources
|
||||
Locale string // default locale
|
||||
Autocomplete bool // default autocomplete
|
||||
SiteStatCode template.HTML // site statistic code
|
||||
ReadOnly bool // read-only mode
|
||||
OAuthLoginURL string
|
||||
OAuthAccessTokenURL string
|
||||
OAuthUserInfoURL string
|
||||
OAuthClientID string
|
||||
OAuthClientSecret string
|
||||
}
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
// Wide configurations.
|
||||
var Wide *conf
|
||||
|
@ -83,18 +88,14 @@ var Docker bool
|
|||
const DockerImageGo = "golang"
|
||||
|
||||
// Load loads the Wide configurations from wide.json and users' configurations from users/{userId}.json.
|
||||
func Load(confPath, confData, confServer, confLogLevel string) {
|
||||
initWide(confPath, confData, confServer, confLogLevel)
|
||||
func Load(confPath, confData, confServer, confLogLevel, confReadOnly string, confSiteStatCode template.HTML) {
|
||||
initWide(confPath, confData, confServer, confLogLevel, confReadOnly, confSiteStatCode)
|
||||
initUsers()
|
||||
|
||||
cmd := exec.Command("docker", "version")
|
||||
_, err := cmd.CombinedOutput()
|
||||
if nil != err {
|
||||
if !util.OS.IsWindows() {
|
||||
logger.Errorf("Not found 'docker' installed, running user's code will cause security problem")
|
||||
|
||||
os.Exit(-1)
|
||||
}
|
||||
logger.Warnf("Not found 'docker' installed, running user's code will cause security problem")
|
||||
} else {
|
||||
Docker = true
|
||||
}
|
||||
|
@ -127,7 +128,7 @@ func initUsers() {
|
|||
|
||||
user := &User{}
|
||||
|
||||
bytes, _ := ioutil.ReadFile(filepath.Join(Wide.Data, "users", name))
|
||||
bytes, _ := os.ReadFile(filepath.Join(Wide.Data, "users", name))
|
||||
err := json.Unmarshal(bytes, user)
|
||||
if err != nil {
|
||||
logger.Errorf("Parses [%s] error: %v, skip loading this user", name, err)
|
||||
|
@ -141,15 +142,15 @@ func initUsers() {
|
|||
}
|
||||
|
||||
// Compatibility upgrade (1.5.3): https://github.com/b3log/wide/issues/308
|
||||
if "" == user.GoBuildArgsForLinux {
|
||||
user.GoBuildArgsForLinux = "-i"
|
||||
}
|
||||
if "" == user.GoBuildArgsForWindows {
|
||||
user.GoBuildArgsForWindows = "-i"
|
||||
}
|
||||
if "" == user.GoBuildArgsForDarwin {
|
||||
user.GoBuildArgsForDarwin = "-i"
|
||||
}
|
||||
//if "" == user.GoBuildArgsForLinux {
|
||||
// user.GoBuildArgsForLinux = "-i"
|
||||
//}
|
||||
//if "" == user.GoBuildArgsForWindows {
|
||||
// user.GoBuildArgsForWindows = "-i"
|
||||
//}
|
||||
//if "" == user.GoBuildArgsForDarwin {
|
||||
// user.GoBuildArgsForDarwin = "-i"
|
||||
//}
|
||||
|
||||
Users = append(Users, user)
|
||||
}
|
||||
|
@ -158,8 +159,8 @@ func initUsers() {
|
|||
initCustomizedConfs()
|
||||
}
|
||||
|
||||
func initWide(confPath, confData, confServer, confLogLevel string) {
|
||||
bytes, err := ioutil.ReadFile(confPath)
|
||||
func initWide(confPath, confData, confServer, confLogLevel, confReadOnly string, confSiteStatCode template.HTML) {
|
||||
bytes, err := os.ReadFile(confPath)
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
|
@ -175,17 +176,19 @@ func initWide(confPath, confData, confServer, confLogLevel string) {
|
|||
os.Exit(-1)
|
||||
}
|
||||
|
||||
Wide.Autocomplete = true // default to true
|
||||
|
||||
// Logging Level
|
||||
log.SetLevel(Wide.LogLevel)
|
||||
gulu.Log.SetLevel(Wide.LogLevel)
|
||||
if "" != confLogLevel {
|
||||
Wide.LogLevel = confLogLevel
|
||||
log.SetLevel(confLogLevel)
|
||||
gulu.Log.SetLevel(confLogLevel)
|
||||
}
|
||||
|
||||
logger.Debug("Conf: \n" + string(bytes))
|
||||
|
||||
// User Home
|
||||
home, err := util.OS.Home()
|
||||
home, err := gulu.OS.Home()
|
||||
if nil != err {
|
||||
logger.Error("Can't get user's home, please report this issue to developer", err)
|
||||
|
||||
|
@ -220,6 +223,15 @@ func initWide(confPath, confData, confServer, confLogLevel string) {
|
|||
Wide.Server = confServer
|
||||
}
|
||||
|
||||
if "" != confReadOnly {
|
||||
Wide.ReadOnly, _ = strconv.ParseBool(confReadOnly)
|
||||
}
|
||||
|
||||
// SiteStatCode
|
||||
if "" != confSiteStatCode {
|
||||
Wide.SiteStatCode = confSiteStatCode
|
||||
}
|
||||
|
||||
time := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
logger.Debugf("${time} [%s]", time)
|
||||
Wide.StaticResourceVersion = strings.Replace(Wide.StaticResourceVersion, "${time}", time, 1)
|
||||
|
@ -233,14 +245,14 @@ func FixedTimeCheckEnv() {
|
|||
checkEnv() // check immediately
|
||||
|
||||
go func() {
|
||||
for _ = range time.Tick(time.Minute*7) {
|
||||
for _ = range time.Tick(time.Minute * 7) {
|
||||
checkEnv()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func checkEnv() {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
cmd := exec.Command("go", "version")
|
||||
buf, err := cmd.CombinedOutput()
|
||||
|
@ -257,16 +269,16 @@ func checkEnv() {
|
|||
os.Exit(-1)
|
||||
}
|
||||
|
||||
gocode := util.Go.GetExecutableInGOBIN("gocode")
|
||||
gocode := gulu.Go.GetExecutableInGOBIN("gocode")
|
||||
cmd = exec.Command(gocode)
|
||||
_, err = cmd.Output()
|
||||
if nil != err {
|
||||
event.EventQueue <- &event.Event{Code: event.EvtCodeGocodeNotFound}
|
||||
|
||||
logger.Warnf("Not found gocode [%s], please install it with this command: go get github.com/nsf/gocode", gocode)
|
||||
logger.Warnf("Not found gocode [%s], please install it with this command: go get github.com/stamblerre/gocode", gocode)
|
||||
}
|
||||
|
||||
ideStub := util.Go.GetExecutableInGOBIN("gotools")
|
||||
ideStub := gulu.Go.GetExecutableInGOBIN("gotools")
|
||||
cmd = exec.Command(ideStub, "version")
|
||||
_, err = cmd.Output()
|
||||
if nil != err {
|
||||
|
@ -295,7 +307,7 @@ func GetGoFmt(userId string) string {
|
|||
case "gofmt":
|
||||
return "gofmt"
|
||||
case "goimports":
|
||||
return util.Go.GetExecutableInGOBIN("goimports")
|
||||
return gulu.Go.GetExecutableInGOBIN("goimports")
|
||||
default:
|
||||
logger.Errorf("Unsupported Go Format tool [%s]", user.GoFormat)
|
||||
return "gofmt"
|
||||
|
@ -405,7 +417,7 @@ func CreateWorkspaceDir(path string) {
|
|||
|
||||
// createDir creates a directory on the path if it not exists.
|
||||
func createDir(path string) {
|
||||
if !util.File.IsExist(path) {
|
||||
if !gulu.File.IsExist(path) {
|
||||
if err := os.MkdirAll(path, 0775); nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
|
|
|
@ -2,9 +2,15 @@
|
|||
"Server": "http://127.0.0.1:7070",
|
||||
"LogLevel": "debug",
|
||||
"Data": "${home}/wide",
|
||||
"RuntimeMode": "dev",
|
||||
"RuntimeMode": "prod",
|
||||
"HTTPSessionMaxAge": 86400,
|
||||
"StaticResourceVersion": "${time}",
|
||||
"Locale": "zh_CN",
|
||||
"Autocomplete": true
|
||||
"SiteStatCode": "",
|
||||
"ReadOnly": false,
|
||||
"OAuthLoginURL": "",
|
||||
"OAuthAccessTokenURL": "",
|
||||
"OAuthUserInfoURL": "",
|
||||
"OAuthClientID": "",
|
||||
"OAuthClientSecret": ""
|
||||
}
|
24
coverage.sh
24
coverage.sh
|
@ -1,24 +0,0 @@
|
|||
#!/bin/bash
|
||||
# see https://gist.github.com/hailiang/0f22736320abe6be71ce for more details
|
||||
|
||||
set -e
|
||||
|
||||
# Run test coverage on each subdirectories and merge the coverage profile.
|
||||
|
||||
echo "mode: count" > profile.cov
|
||||
|
||||
# Standard go tooling behavior is to ignore dirs with leading underscors
|
||||
for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -not -path './vendor*' -type d);
|
||||
do
|
||||
if ls $dir/*.go &> /dev/null; then
|
||||
go test -covermode=count -coverprofile=$dir/profile.tmp $dir
|
||||
if [ -f $dir/profile.tmp ]
|
||||
then
|
||||
cat $dir/profile.tmp | tail -n +2 >> profile.cov
|
||||
rm $dir/profile.tmp
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
go tool cover -func profile.cov
|
||||
|
|
@ -25,85 +25,24 @@ import (
|
|||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/file"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/file"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
|
||||
// WSHandler handles request of creating editor channel.
|
||||
// XXX: NOT used at present
|
||||
func WSHandler(w http.ResponseWriter, r *http.Request) {
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
sid := httpSession.Values["id"].(string)
|
||||
|
||||
conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024)
|
||||
editorChan := util.WSChannel{Sid: sid, Conn: conn, Request: r, Time: time.Now()}
|
||||
|
||||
ret := map[string]interface{}{"output": "Editor initialized", "cmd": "init-editor"}
|
||||
err := editorChan.WriteJSON(&ret)
|
||||
if nil != err {
|
||||
return
|
||||
}
|
||||
|
||||
session.EditorWS[sid] = &editorChan
|
||||
|
||||
logger.Tracef("Open a new [Editor] with session [%s], %d", sid, len(session.EditorWS))
|
||||
|
||||
args := map[string]interface{}{}
|
||||
for {
|
||||
if err := session.EditorWS[sid].ReadJSON(&args); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
code := args["code"].(string)
|
||||
line := int(args["cursorLine"].(float64))
|
||||
ch := int(args["cursorCh"].(float64))
|
||||
|
||||
offset := getCursorOffset(code, line, ch)
|
||||
|
||||
logger.Tracef("offset: %d", offset)
|
||||
|
||||
gocode := util.Go.GetExecutableInGOBIN("gocode")
|
||||
argv := []string{"-f=json", "autocomplete", strconv.Itoa(offset)}
|
||||
|
||||
var output bytes.Buffer
|
||||
|
||||
cmd := exec.Command(gocode, argv...)
|
||||
cmd.Stdout = &output
|
||||
|
||||
stdin, _ := cmd.StdinPipe()
|
||||
cmd.Start()
|
||||
stdin.Write([]byte(code))
|
||||
stdin.Close()
|
||||
cmd.Wait()
|
||||
|
||||
ret = map[string]interface{}{"output": string(output.Bytes()), "cmd": "autocomplete"}
|
||||
|
||||
if err := session.EditorWS[sid].WriteJSON(&ret); err != nil {
|
||||
logger.Error("Editor WS ERROR: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
// AutocompleteHandler handles request of code autocompletion.
|
||||
func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var args map[string]interface{}
|
||||
if conf.Wide.ReadOnly {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
@ -120,9 +59,7 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
uid := session.Values["uid"].(string)
|
||||
|
||||
path := args["path"].(string)
|
||||
|
||||
fout, err := os.Create(path)
|
||||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
@ -132,7 +69,6 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
code := args["code"].(string)
|
||||
fout.WriteString(code)
|
||||
|
||||
if err := fout.Close(); nil != err {
|
||||
logger.Error(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
@ -142,9 +78,7 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
line := int(args["cursorLine"].(float64))
|
||||
ch := int(args["cursorCh"].(float64))
|
||||
|
||||
offset := getCursorOffset(code, line, ch)
|
||||
|
||||
logger.Tracef("offset: %d", offset)
|
||||
|
||||
userWorkspace := conf.GetUserWorkspace(uid)
|
||||
|
@ -158,8 +92,8 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
logger.Tracef("gocode set lib-path [%s]", libPath)
|
||||
|
||||
gocode := gulu.Go.GetExecutableInGOBIN("gocode")
|
||||
// FIXME: using gocode set lib-path has some issues while accrossing workspaces
|
||||
gocode := util.Go.GetExecutableInGOBIN("gocode")
|
||||
exec.Command(gocode, []string{"set", "lib-path", libPath}...).Run()
|
||||
|
||||
argv := []string{"-f=json", "--in=" + path, "autocomplete", strconv.Itoa(offset)}
|
||||
|
@ -179,8 +113,8 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// GetExprInfoHandler handles request of getting expression infomation.
|
||||
func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
uid := session.Values["uid"].(string)
|
||||
|
@ -201,7 +135,7 @@ func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -211,7 +145,7 @@ func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := fout.Close(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -223,7 +157,7 @@ func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
logger.Tracef("offset [%d]", offset)
|
||||
|
||||
ideStub := util.Go.GetExecutableInGOBIN("gotools")
|
||||
ideStub := gulu.Go.GetExecutableInGOBIN("gotools")
|
||||
argv := []string{"types", "-pos", filename + ":" + strconv.Itoa(offset), "-info", "."}
|
||||
cmd := exec.Command(ideStub, argv...)
|
||||
cmd.Dir = curDir
|
||||
|
@ -240,7 +174,7 @@ func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
exprInfo := strings.TrimSpace(string(output))
|
||||
if "" == exprInfo {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -250,8 +184,8 @@ func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// FindDeclarationHandler handles request of finding declaration.
|
||||
func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
|
@ -277,7 +211,7 @@ func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -287,7 +221,7 @@ func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := fout.Close(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -299,7 +233,7 @@ func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
logger.Tracef("offset [%d]", offset)
|
||||
|
||||
ideStub := util.Go.GetExecutableInGOBIN("gotools")
|
||||
ideStub := gulu.Go.GetExecutableInGOBIN("gotools")
|
||||
argv := []string{"types", "-pos", filename + ":" + strconv.Itoa(offset), "-def", "."}
|
||||
cmd := exec.Command(ideStub, argv...)
|
||||
cmd.Dir = curDir
|
||||
|
@ -316,7 +250,7 @@ func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
found := strings.TrimSpace(string(output))
|
||||
if "" == found {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -338,8 +272,8 @@ func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// FindUsagesHandler handles request of finding usages.
|
||||
func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
|
@ -366,7 +300,7 @@ func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -376,7 +310,7 @@ func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := fout.Close(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -387,7 +321,7 @@ func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
offset := getCursorOffset(code, line, ch)
|
||||
logger.Tracef("offset [%d]", offset)
|
||||
|
||||
ideStub := util.Go.GetExecutableInGOBIN("gotools")
|
||||
ideStub := gulu.Go.GetExecutableInGOBIN("gotools")
|
||||
argv := []string{"types", "-pos", filename + ":" + strconv.Itoa(offset), "-use", "."}
|
||||
cmd := exec.Command(ideStub, argv...)
|
||||
cmd.Dir = curDir
|
||||
|
@ -404,7 +338,7 @@ func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
out := strings.TrimSpace(string(output))
|
||||
if "" == out {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// GoFmtHandler handles request of formatting Go source code.
|
||||
|
@ -31,8 +31,14 @@ import (
|
|||
// 1. gofmt
|
||||
// 2. goimports
|
||||
func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
if conf.Wide.ReadOnly {
|
||||
result.Code = -1
|
||||
result.Msg = "readonly mode"
|
||||
return
|
||||
}
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
|
@ -46,15 +52,15 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
filePath := args["file"].(string)
|
||||
|
||||
if util.Go.IsAPI(filePath) {
|
||||
result.Succ = false
|
||||
if gulu.Go.IsAPI(filePath) {
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -63,7 +69,7 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -73,7 +79,7 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
|
|||
fout.WriteString(code)
|
||||
if err := fout.Close(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -94,7 +100,7 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
|
|||
output := string(bytes)
|
||||
if "" == output {
|
||||
// format error, returns the original content
|
||||
result.Succ = true
|
||||
result.Code = 0
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -106,7 +112,7 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
|
|||
fout.WriteString(code)
|
||||
if err := fout.Close(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ package event
|
|||
import (
|
||||
"os"
|
||||
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -39,7 +38,7 @@ const (
|
|||
const maxQueueLength = 10
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
// Event represents an event.
|
||||
type Event struct {
|
||||
|
@ -70,7 +69,7 @@ var UserEventQueues = queues{}
|
|||
// Load initializes the event handling.
|
||||
func Load() {
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
for event := range EventQueue {
|
||||
logger.Debugf("Received a global event [code=%d]", event.Code)
|
||||
|
@ -107,7 +106,7 @@ func (ueqs queues) New(sid string) *UserEventQueue {
|
|||
ueqs[sid] = q
|
||||
|
||||
go func() { // start listening
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
for evt := range q.Queue {
|
||||
logger.Debugf("Session [%s] received an event [%d]", sid, evt.Code)
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
)
|
||||
|
||||
// GetZipHandler handles request of retrieving zip file.
|
||||
|
@ -34,7 +34,7 @@ func GetZipHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !util.File.IsExist(path) {
|
||||
if !gulu.File.IsExist(path) {
|
||||
http.Error(w, "Not Found", 404)
|
||||
|
||||
return
|
||||
|
@ -51,13 +51,13 @@ func GetZipHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// CreateZipHandler handles request of creating zip.
|
||||
func CreateZipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data := util.NewResult()
|
||||
defer util.RetResult(w, r, data)
|
||||
data := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, data)
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
data.Succ = false
|
||||
data.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -75,24 +75,24 @@ func CreateZipHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
dir := filepath.Dir(path)
|
||||
|
||||
if !util.File.IsExist(path) {
|
||||
data.Succ = false
|
||||
if !gulu.File.IsExist(path) {
|
||||
data.Code = -1
|
||||
data.Msg = "Can't find file [" + path + "]"
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
zipPath := filepath.Join(dir, name)
|
||||
zipFile, err := util.Zip.Create(zipPath + ".zip")
|
||||
zipFile, err := gulu.Zip.Create(zipPath + ".zip")
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
data.Succ = false
|
||||
data.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
defer zipFile.Close()
|
||||
|
||||
if util.File.IsDir(path) {
|
||||
if gulu.File.IsDir(path) {
|
||||
zipFile.AddDirectory(base, path)
|
||||
} else {
|
||||
zipFile.AddEntry(base, path)
|
||||
|
|
115
file/files.go
115
file/files.go
|
@ -24,15 +24,14 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/event"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/event"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
// Node represents a file node in file tree.
|
||||
type Node struct {
|
||||
|
@ -61,7 +60,7 @@ var apiNode *Node
|
|||
|
||||
// initAPINode builds the Go API file node.
|
||||
func initAPINode() {
|
||||
apiPath := util.Go.GetAPIPath()
|
||||
apiPath := gulu.Go.GetAPIPath()
|
||||
|
||||
apiNode = &Node{Name: "Go API", Path: apiPath, IconSkin: "ico-ztree-dir-api ", Type: "d",
|
||||
Creatable: false, Removable: false, IsGoAPI: true, Children: []*Node{}}
|
||||
|
@ -82,8 +81,8 @@ func GetFilesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetGzResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetGzResult(w, r, result)
|
||||
|
||||
userWorkspace := conf.GetUserWorkspace(uid)
|
||||
workspaces := filepath.SplitList(userWorkspace)
|
||||
|
@ -134,7 +133,7 @@ func RefreshDirectoryHandler(w http.ResponseWriter, r *http.Request) {
|
|||
r.ParseForm()
|
||||
path := r.FormValue("path")
|
||||
|
||||
if !util.Go.IsAPI(path) && !session.CanAccess(uid, path) {
|
||||
if !gulu.Go.IsAPI(path) && !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -164,29 +163,29 @@ func GetFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
path := args["path"].(string)
|
||||
|
||||
if !util.Go.IsAPI(path) && !session.CanAccess(uid, path) {
|
||||
if !gulu.Go.IsAPI(path) && !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
size := util.File.GetFileSize(path)
|
||||
size := gulu.File.GetFileSize(path)
|
||||
if size > 5242880 { // 5M
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
result.Msg = "This file is too large to open :("
|
||||
|
||||
return
|
||||
|
@ -199,7 +198,7 @@ func GetFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
extension := filepath.Ext(path)
|
||||
|
||||
if util.File.IsImg(extension) {
|
||||
if gulu.File.IsImg(extension) {
|
||||
// image file will be open in a browser tab
|
||||
|
||||
data["mode"] = "img"
|
||||
|
@ -221,8 +220,8 @@ func GetFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
content := string(buf)
|
||||
|
||||
if util.File.IsBinary(content) {
|
||||
result.Succ = false
|
||||
if gulu.File.IsBinary(content) {
|
||||
result.Code = -1
|
||||
result.Msg = "Can't open a binary file :("
|
||||
} else {
|
||||
data["content"] = content
|
||||
|
@ -240,14 +239,20 @@ func SaveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
if conf.Wide.ReadOnly {
|
||||
result.Code = -1
|
||||
result.Msg = "readonly mode"
|
||||
return
|
||||
}
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -255,7 +260,7 @@ func SaveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
filePath := args["file"].(string)
|
||||
sid := args["sid"].(string)
|
||||
|
||||
if util.Go.IsAPI(filePath) || !session.CanAccess(uid, filePath) {
|
||||
if gulu.Go.IsAPI(filePath) || !session.CanAccess(uid, filePath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -265,7 +270,7 @@ func SaveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -276,7 +281,7 @@ func SaveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := fout.Close(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
wSession := session.WideSessions.Get(sid)
|
||||
wSession.EventQueue.Queue <- &event.Event{Code: event.EvtCodeServerInternalError, Sid: sid,
|
||||
|
@ -296,21 +301,21 @@ func NewFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
path := args["path"].(string)
|
||||
|
||||
if util.Go.IsAPI(path) || !session.CanAccess(uid, path) {
|
||||
if gulu.Go.IsAPI(path) || !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -322,7 +327,7 @@ func NewFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
wSession := session.WideSessions.Get(sid)
|
||||
|
||||
if !createFile(path, fileType) {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
wSession.EventQueue.Queue <- &event.Event{Code: event.EvtCodeServerInternalError, Sid: sid,
|
||||
Data: "can't create file " + path}
|
||||
|
@ -348,21 +353,21 @@ func RemoveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
path := args["path"].(string)
|
||||
|
||||
if util.Go.IsAPI(path) || !session.CanAccess(uid, path) {
|
||||
if gulu.Go.IsAPI(path) || !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -373,7 +378,7 @@ func RemoveFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
wSession := session.WideSessions.Get(sid)
|
||||
|
||||
if !removeFile(path) {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
wSession.EventQueue.Queue <- &event.Event{Code: event.EvtCodeServerInternalError, Sid: sid,
|
||||
Data: "can't remove file " + path}
|
||||
|
@ -394,20 +399,20 @@ func RenameFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
oldPath := args["oldPath"].(string)
|
||||
if util.Go.IsAPI(oldPath) ||
|
||||
if gulu.Go.IsAPI(oldPath) ||
|
||||
!session.CanAccess(uid, oldPath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
|
@ -415,7 +420,7 @@ func RenameFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
newPath := args["newPath"].(string)
|
||||
if util.Go.IsAPI(newPath) || !session.CanAccess(uid, newPath) {
|
||||
if gulu.Go.IsAPI(newPath) || !session.CanAccess(uid, newPath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -426,7 +431,7 @@ func RenameFileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
wSession := session.WideSessions.Get(sid)
|
||||
|
||||
if !renameFile(oldPath, newPath) {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
wSession.EventQueue.Queue <- &event.Event{Code: event.EvtCodeServerInternalError, Sid: sid,
|
||||
Data: "can't rename file " + oldPath}
|
||||
|
@ -459,19 +464,19 @@ func FindHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
path := args["path"].(string) // path of selected file in file tree
|
||||
if !util.Go.IsAPI(path) && !session.CanAccess(uid, path) {
|
||||
if !gulu.Go.IsAPI(path) && !session.CanAccess(uid, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -482,7 +487,7 @@ func FindHandler(w http.ResponseWriter, r *http.Request) {
|
|||
userWorkspace := conf.GetUserWorkspace(uid)
|
||||
workspaces := filepath.SplitList(userWorkspace)
|
||||
|
||||
if "" != path && !util.File.IsDir(path) {
|
||||
if "" != path && !gulu.File.IsDir(path) {
|
||||
path = filepath.Dir(path)
|
||||
}
|
||||
|
||||
|
@ -492,7 +497,7 @@ func FindHandler(w http.ResponseWriter, r *http.Request) {
|
|||
rs := find(workspace+conf.PathSeparator+"src", name, []*string{})
|
||||
|
||||
for _, r := range rs {
|
||||
substr := util.Str.LCS(path, *r)
|
||||
substr := gulu.Str.LCS(path, *r)
|
||||
|
||||
founds = append(founds, &foundPath{Path: filepath.ToSlash(*r), score: len(substr)})
|
||||
}
|
||||
|
@ -512,14 +517,14 @@ func SearchTextHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -527,7 +532,7 @@ func SearchTextHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sid := args["sid"].(string)
|
||||
wSession := session.WideSessions.Get(sid)
|
||||
if nil == wSession {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -545,7 +550,7 @@ func SearchTextHandler(w http.ResponseWriter, r *http.Request) {
|
|||
text := args["text"].(string)
|
||||
|
||||
founds := []*Snippet{}
|
||||
if util.File.IsDir(dir) {
|
||||
if gulu.File.IsDir(dir) {
|
||||
founds = search(dir, extension, text, []*Snippet{})
|
||||
} else {
|
||||
founds = searchInFile(dir, text)
|
||||
|
@ -644,7 +649,7 @@ func listFiles(dirname string) []string {
|
|||
//
|
||||
// Refers to the zTree document for CSS class names.
|
||||
func getIconSkin(filenameExtension string) string {
|
||||
if util.File.IsImg(filenameExtension) {
|
||||
if gulu.File.IsImg(filenameExtension) {
|
||||
return "ico-ztree-img "
|
||||
}
|
||||
|
||||
|
@ -763,7 +768,7 @@ func find(dir, name string, results []*string) []*string {
|
|||
path := dir + fname
|
||||
|
||||
if fileInfo.IsDir() {
|
||||
if util.Str.Contains(fname, defaultExcludesFind) {
|
||||
if gulu.Str.Contains(fname, defaultExcludesFind) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -836,7 +841,7 @@ func searchInFile(path string, text string) []*Snippet {
|
|||
}
|
||||
|
||||
content := string(bytes)
|
||||
if util.File.IsBinary(content) {
|
||||
if gulu.File.IsBinary(content) {
|
||||
return ret
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
)
|
||||
|
||||
type element struct {
|
||||
|
@ -34,14 +34,14 @@ type element struct {
|
|||
|
||||
// GetOutlineHandler gets outfile of a go file.
|
||||
func GetOutlineHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ func GetOutlineHandler(w http.ResponseWriter, r *http.Request) {
|
|||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, "", code, 0)
|
||||
if err != nil {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
|
36
go.mod
36
go.mod
|
@ -1,21 +1,23 @@
|
|||
module github.com/b3log/wide
|
||||
module github.com/88250/wide
|
||||
|
||||
go 1.12
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/gorilla/context v0.0.0-20141217160251-215affda49ad // indirect
|
||||
github.com/gorilla/securecookie v0.0.0-20150327155805-8e98dd730fc4 // indirect
|
||||
github.com/gorilla/sessions v0.0.0-20150417174705-f61c3ec2cf65
|
||||
github.com/gorilla/websocket v0.0.0-20150530030352-a3ec486e6a7a
|
||||
github.com/hashicorp/go-version v1.2.0
|
||||
github.com/moul/http2curl v1.0.0 // indirect
|
||||
github.com/parnurzeal/gorequest v0.2.15
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
|
||||
golang.org/x/net v0.0.0-20190514140710-3ec191127204 // indirect
|
||||
golang.org/x/sys v0.0.0-20190515190549-87c872767d25 // indirect
|
||||
golang.org/x/text v0.3.2
|
||||
github.com/88250/gulu v1.1.0
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/gorilla/sessions v1.2.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/parnurzeal/gorequest v0.2.16
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davidebianchi/go-jsonclient v1.5.0 // indirect
|
||||
github.com/elazarl/goproxy v0.0.0-20200426045556-49ad98f6dac1 // indirect
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect
|
||||
golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b // indirect
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
moul.io/http2curl v1.0.0 // indirect
|
||||
)
|
||||
|
|
57
go.sum
57
go.sum
|
@ -1,43 +1,44 @@
|
|||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ3dbHb5sA6YZWXFORQYZx5sdsTlMs=
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhPhOPHULCQQDnGhRelpFWHMLhQVWDsS0v4=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/88250/gulu v1.1.0 h1:aU8HncW1XNssT1insCOz6rvmTUDrtsDwSnzeqTEqNFA=
|
||||
github.com/88250/gulu v1.1.0/go.mod h1:a2POIziN+QFeNT4Mj7FHH2lz1HEaFlMRF6wPE0NHM4U=
|
||||
github.com/davidebianchi/go-jsonclient v1.5.0 h1:PVDunAF/6c30D2SSx711efsrUP3hhml+uGT6oD3lzVY=
|
||||
github.com/davidebianchi/go-jsonclient v1.5.0/go.mod h1:lXd/hkx23H590Dod74j5GsmpgxF8RIAGZDt1P5+2mqo=
|
||||
github.com/elazarl/goproxy v0.0.0-20200426045556-49ad98f6dac1 h1:TEmChtx8+IeOghiySC8kQIr0JZOdKUmRmmkuRDuYs3E=
|
||||
github.com/elazarl/goproxy v0.0.0-20200426045556-49ad98f6dac1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v0.0.0-20141217160251-215affda49ad h1:wJwKN6X6iRRVnjdBgrkWjhBOvYm7yw5boqXwFUnBtbE=
|
||||
github.com/gorilla/context v0.0.0-20141217160251-215affda49ad/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/securecookie v0.0.0-20150327155805-8e98dd730fc4 h1:X0DbEdoaUJT+NZ8mLHRNMSLmogzqLhsA1Eh6gs7Y7Zg=
|
||||
github.com/gorilla/securecookie v0.0.0-20150327155805-8e98dd730fc4/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v0.0.0-20150417174705-f61c3ec2cf65 h1:bDPV+Nh80WIp0U0a/o9wKilWRxH+l8jIySjElU91LeA=
|
||||
github.com/gorilla/sessions v0.0.0-20150417174705-f61c3ec2cf65/go.mod h1:+WVp8kdw6VhyKExm03PAMRn2ZxnPtm58pV0dBVPdhHE=
|
||||
github.com/gorilla/websocket v0.0.0-20150530030352-a3ec486e6a7a h1:p/PGT+3UGSK7eULOGHUMCUxI5U976R34HWuKHbFpK3Q=
|
||||
github.com/gorilla/websocket v0.0.0-20150530030352-a3ec486e6a7a/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
|
||||
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
|
||||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||
github.com/parnurzeal/gorequest v0.2.15 h1:oPjDCsF5IkD4gUk6vIgsxYNaSgvAnIh1EJeROn3HdJU=
|
||||
github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/parnurzeal/gorequest v0.2.16 h1:T/5x+/4BT+nj+3eSknXmCTnEVGSzFzPGdpqmUVVZXHQ=
|
||||
github.com/parnurzeal/gorequest v0.2.16/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190514140710-3ec191127204 h1:4yG6GqBtw9C+UrLp6s2wtSniayy/Vd/3F7ffLE427XI=
|
||||
golang.org/x/net v0.0.0-20190514140710-3ec191127204/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190515190549-87c872767d25 h1:SSKQq5sjDoW0L0NaDoVl7d7HmtTxM0ezm0Ef9azs4uQ=
|
||||
golang.org/x/sys v0.0.0-20190515190549-87c872767d25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b h1:h03Ur1RlPrGTjua4koYdpGl8W0eYo8p1uI9w7RPlkdk=
|
||||
golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
*/
|
||||
var gulp = require('gulp')
|
||||
var concat = require('gulp-concat')
|
||||
var minifyCSS = require('gulp-minify-css')
|
||||
var cleanCSS = require('gulp-clean-css')
|
||||
var uglify = require('gulp-uglify')
|
||||
var sourcemaps = require('gulp-sourcemaps')
|
||||
|
||||
|
@ -37,14 +37,14 @@ function minLibCSS () {
|
|||
'./static/js/lib/codemirror-5.1/addon/dialog/dialog.css',
|
||||
'./static/js/overwrite/codemirror/theme/*.css']
|
||||
return gulp.src(cssLibs).
|
||||
pipe(minifyCSS()).
|
||||
pipe(cleanCSS()).
|
||||
pipe(concat('lib.min.css')).
|
||||
pipe(gulp.dest('./static/css/'))
|
||||
}
|
||||
|
||||
function minZTreeStyleCSS () {
|
||||
return gulp.src('./static/js/lib/ztree/zTreeStyle.css').
|
||||
pipe(minifyCSS()).
|
||||
pipe(cleanCSS()).
|
||||
pipe(concat('zTreeStyle.min.css')).
|
||||
pipe(gulp.dest('./static/js/lib/ztree/'))
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ function minWideCSS () {
|
|||
]
|
||||
|
||||
return gulp.src(cssWide).
|
||||
pipe(minifyCSS()).
|
||||
pipe(cleanCSS()).
|
||||
pipe(concat('wide.min.css')).
|
||||
pipe(gulp.dest('./static/css/'))
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
"close_all_files": "Close All",
|
||||
"save_all_files": "Save All",
|
||||
"format": "Format",
|
||||
"gomod": "go mod",
|
||||
"goinstall": "go install",
|
||||
"build": "Build",
|
||||
"build_n_run": "Build&Run",
|
||||
|
@ -102,9 +101,6 @@
|
|||
"start-install": "START [go install]",
|
||||
"install-succ": "[go install] SUCCESS",
|
||||
"install-error": "[go install] ERROR",
|
||||
"start-mod": "START [go mod]",
|
||||
"mod-succ": "[go mod] SUCCESS",
|
||||
"mod-error": "[go mod] ERROR",
|
||||
"check_version": "Checking update",
|
||||
"new_version_available": "new version available",
|
||||
"go_env": "Go",
|
||||
|
@ -170,5 +166,6 @@
|
|||
"download": "Download",
|
||||
"decompress": "Decompress",
|
||||
"keymap": "Keymap",
|
||||
"resize": "Resize"
|
||||
"resize": "Resize",
|
||||
"sponsor": "Sponsor"
|
||||
}
|
|
@ -28,7 +28,6 @@
|
|||
"close_all_files": "全てのファイルを閉じる",
|
||||
"save_all_files": "全てを保存",
|
||||
"format": "フォーマット",
|
||||
"gomod": "go mod",
|
||||
"goinstall": "go install",
|
||||
"build": "ビルド",
|
||||
"build_n_run": "ビルド実行",
|
||||
|
@ -102,9 +101,6 @@
|
|||
"start-install": "[go install] 開始",
|
||||
"install-succ": "[go install] 成功",
|
||||
"install-error": "[go install] 失敗",
|
||||
"start-mod": "[go mod] 開始",
|
||||
"mod-succ": "[go mod] 成功",
|
||||
"mod-error": "[go mod] 失敗",
|
||||
"check_version": "更新をチェック中",
|
||||
"new_version_available": "新しいバージョンがあります",
|
||||
"go_env": "Go",
|
||||
|
@ -159,9 +155,9 @@
|
|||
"search_no_match": "一致するファイルが見つかりませんでした。",
|
||||
"outline": "アウトライン",
|
||||
"govet": "go vet",
|
||||
"start-vet": "START [go vet]",
|
||||
"vet-succ": "[go vet] SUCCESS",
|
||||
"vet-error": "[go vet] ERROR",
|
||||
"start-vet": "[go vet] 開始",
|
||||
"vet-succ": "[go vet] 成功",
|
||||
"vet-error": "[go vet] 失敗",
|
||||
"restore_outline": "アウトラインを復元",
|
||||
"share": "シェア",
|
||||
"url": "リンク",
|
||||
|
@ -170,5 +166,6 @@
|
|||
"download": "ダウンロード",
|
||||
"decompress": "解凍する",
|
||||
"keymap": "キーマップ",
|
||||
"resize": "サイズ変更"
|
||||
"resize": "サイズ変更",
|
||||
"sponsor": "スポンサー"
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
"close_all_files": "모두 닫기",
|
||||
"save_all_files": "일괄저장",
|
||||
"format": "포멧",
|
||||
"gomod": "go mod",
|
||||
"goinstall": "go install",
|
||||
"build": "빌드",
|
||||
"build_n_run": "빌드후실행",
|
||||
|
@ -102,9 +101,6 @@
|
|||
"start-install": "시작 [go install]",
|
||||
"install-succ": "[go install] 성공",
|
||||
"install-error": "[go install] 실패",
|
||||
"start-mod": "시작 [go mod]",
|
||||
"mod-succ": "[go mod] 성공",
|
||||
"mod-error": "[go mod] 실패",
|
||||
"check_version": "최신버전검색중",
|
||||
"new_version_available": "최신업데이트 사용 가능",
|
||||
"go_env": "Go 환경",
|
||||
|
@ -159,9 +155,9 @@
|
|||
"search_no_match": "해당 문서를 찾지 못하였습니다.",
|
||||
"outline": "주제",
|
||||
"govet": "go vet",
|
||||
"start-vet": "START [go vet]",
|
||||
"vet-succ": "[go vet] SUCCESS",
|
||||
"vet-error": "[go vet] ERROR",
|
||||
"start-vet": "시작 [go vet]",
|
||||
"vet-succ": "[go vet] 성공",
|
||||
"vet-error": "[go vet] 실패",
|
||||
"restore_outline": "주제복구",
|
||||
"share": "공유",
|
||||
"url": "하이퍼링크",
|
||||
|
@ -170,5 +166,6 @@
|
|||
"download": "다운로드",
|
||||
"decompress": "압축풀기",
|
||||
"keymap": "단축키",
|
||||
"resize": "크기조절"
|
||||
"resize": "크기조절",
|
||||
"sponsor": "후원사"
|
||||
}
|
||||
|
|
|
@ -17,16 +17,15 @@ package i18n
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/88250/gulu"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
// Locale.
|
||||
type locale struct {
|
||||
|
@ -59,7 +58,7 @@ func Load() {
|
|||
}
|
||||
|
||||
func load(localeStr string) {
|
||||
bytes, err := ioutil.ReadFile("i18n/" + localeStr + ".json")
|
||||
bytes, err := os.ReadFile("i18n/" + localeStr + ".json")
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
"close_all_files": "关闭所有文件",
|
||||
"save_all_files": "保存所有文件",
|
||||
"format": "格式化",
|
||||
"gomod": "go mod",
|
||||
"goinstall": "go install",
|
||||
"build": "构建",
|
||||
"build_n_run": "构建并运行",
|
||||
|
@ -102,9 +101,6 @@
|
|||
"start-install": "开始 [go install]",
|
||||
"install-succ": "[go install] 成功",
|
||||
"install-error": "[go install] 失败",
|
||||
"start-mod": "开始 [go mod]",
|
||||
"mod-succ": "[go mod] 成功",
|
||||
"mod-error": "[go mod] 失败",
|
||||
"check_version": "正在检查更新",
|
||||
"new_version_available": "新版本可用",
|
||||
"go_env": "Go 环境",
|
||||
|
@ -159,9 +155,9 @@
|
|||
"search_no_match": "没有发现匹配的文件。",
|
||||
"outline": "大纲",
|
||||
"govet": "go vet",
|
||||
"start-vet": "START [go vet]",
|
||||
"vet-succ": "[go vet] SUCCESS",
|
||||
"vet-error": "[go vet] ERROR",
|
||||
"start-vet": "开始 [go vet]",
|
||||
"vet-succ": "[go vet] 成功",
|
||||
"vet-error": "[go vet] 失败",
|
||||
"restore_outline": "恢复大纲",
|
||||
"share": "分享",
|
||||
"url": "链接",
|
||||
|
@ -170,5 +166,6 @@
|
|||
"download": "下载",
|
||||
"decompress": "解压缩",
|
||||
"keymap": "快捷键",
|
||||
"resize": "调整大小"
|
||||
"resize": "调整大小",
|
||||
"sponsor": "赞助"
|
||||
}
|
|
@ -28,7 +28,6 @@
|
|||
"close_all_files": "關閉所有檔案",
|
||||
"save_all_files": "儲存所有檔案",
|
||||
"format": "格式化",
|
||||
"gomod": "go mod",
|
||||
"goinstall": "go install",
|
||||
"build": "編譯",
|
||||
"build_n_run": "編譯並執行",
|
||||
|
@ -102,9 +101,6 @@
|
|||
"start-install": "開始 [go install]",
|
||||
"install-succ": "[go install] 成功",
|
||||
"install-error": "[go install] 失敗",
|
||||
"start-mod": "開始 [go mod]",
|
||||
"mod-succ": "[go mod] 成功",
|
||||
"mod-error": "[go mod] 失敗",
|
||||
"check_version": "正在檢查更新",
|
||||
"new_version_available": "可用新版本",
|
||||
"go_env": "Go 環境",
|
||||
|
@ -170,5 +166,6 @@
|
|||
"download": "下載",
|
||||
"decompress": "解壓縮",
|
||||
"keymap": "快速鍵",
|
||||
"resize": "調整大小"
|
||||
"resize": "調整大小",
|
||||
"sponsor": "贊助"
|
||||
}
|
217
log/logs.go
217
log/logs.go
|
@ -1,217 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
// Package log includes logging related manipulations.
|
||||
//
|
||||
// log.SetLevel("debug")
|
||||
// logger := log.NewLogger(os.Stdout)
|
||||
//
|
||||
// logger.Trace("trace message)
|
||||
// logger.Debug("debug message")
|
||||
// logger.Info("info message")
|
||||
// logger.Warn("warning message")
|
||||
// logger.Error("error message")
|
||||
//
|
||||
// logger.Errorf("formatted %s message", "error")
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
stdlog "log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Logging level.
|
||||
const (
|
||||
Off = iota
|
||||
Trace
|
||||
Debug
|
||||
Info
|
||||
Warn
|
||||
Error
|
||||
)
|
||||
|
||||
// all loggers.
|
||||
var loggers []*Logger
|
||||
|
||||
// the global default logging level, it will be used for creating logger.
|
||||
var logLevel = Debug
|
||||
|
||||
// Logger represents a simple logger with level.
|
||||
// The underlying logger is the standard Go logging "log".
|
||||
type Logger struct {
|
||||
level int
|
||||
logger *stdlog.Logger
|
||||
}
|
||||
|
||||
// NewLogger creates a logger.
|
||||
func NewLogger(out io.Writer) *Logger {
|
||||
ret := &Logger{level: logLevel, logger: stdlog.New(out, "", stdlog.Ldate|stdlog.Ltime|stdlog.Lshortfile)}
|
||||
|
||||
loggers = append(loggers, ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// SetLevel sets the logging level of all loggers.
|
||||
func SetLevel(level string) {
|
||||
logLevel = getLevel(level)
|
||||
|
||||
for _, l := range loggers {
|
||||
l.SetLevel(level)
|
||||
}
|
||||
}
|
||||
|
||||
// getLevel gets logging level int value corresponding to the specified level.
|
||||
func getLevel(level string) int {
|
||||
level = strings.ToLower(level)
|
||||
|
||||
switch level {
|
||||
case "off":
|
||||
return Off
|
||||
case "trace":
|
||||
return Trace
|
||||
case "debug":
|
||||
return Debug
|
||||
case "info":
|
||||
return Info
|
||||
case "warn":
|
||||
return Warn
|
||||
case "error":
|
||||
return Error
|
||||
default:
|
||||
return Info
|
||||
}
|
||||
}
|
||||
|
||||
// SetLevel sets the logging level of a logger.
|
||||
func (l *Logger) SetLevel(level string) {
|
||||
l.level = getLevel(level)
|
||||
}
|
||||
|
||||
// IsTraceEnabled determines whether the trace level is enabled.
|
||||
func (l *Logger) IsTraceEnabled() bool {
|
||||
return l.level <= Trace
|
||||
}
|
||||
|
||||
// IsDebugEnabled determines whether the debug level is enabled.
|
||||
func (l *Logger) IsDebugEnabled() bool {
|
||||
return l.level <= Debug
|
||||
}
|
||||
|
||||
// IsWarnEnabled determines whether the debug level is enabled.
|
||||
func (l *Logger) IsWarnEnabled() bool {
|
||||
return l.level <= Warn
|
||||
}
|
||||
|
||||
// Trace prints trace level message.
|
||||
func (l *Logger) Trace(v ...interface{}) {
|
||||
if Trace < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("T ")
|
||||
l.logger.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Tracef prints trace level message with format.
|
||||
func (l *Logger) Tracef(format string, v ...interface{}) {
|
||||
if Trace < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("T ")
|
||||
l.logger.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Debug prints debug level message.
|
||||
func (l *Logger) Debug(v ...interface{}) {
|
||||
if Debug < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("D ")
|
||||
l.logger.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Debugf prints debug level message with format.
|
||||
func (l *Logger) Debugf(format string, v ...interface{}) {
|
||||
if Debug < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("D ")
|
||||
l.logger.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Info prints info level message.
|
||||
func (l *Logger) Info(v ...interface{}) {
|
||||
if Info < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("I ")
|
||||
l.logger.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Infof prints info level message with format.
|
||||
func (l *Logger) Infof(format string, v ...interface{}) {
|
||||
if Info < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("I ")
|
||||
l.logger.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Warn prints warning level message.
|
||||
func (l *Logger) Warn(v ...interface{}) {
|
||||
if Warn < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("W ")
|
||||
l.logger.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Warn prints warning level message with format.
|
||||
func (l *Logger) Warnf(format string, v ...interface{}) {
|
||||
if Warn < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("W ")
|
||||
l.logger.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Error prints error level message.
|
||||
func (l *Logger) Error(v ...interface{}) {
|
||||
if Error < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("E ")
|
||||
l.logger.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Errorf prints error level message with format.
|
||||
func (l *Logger) Errorf(format string, v ...interface{}) {
|
||||
if Error < l.level {
|
||||
return
|
||||
}
|
||||
|
||||
l.logger.SetPrefix("E ")
|
||||
l.logger.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
169
log/logs_test.go
169
log/logs_test.go
|
@ -1,169 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
var logger = NewLogger(os.Stdout)
|
||||
|
||||
func TestSetLevel(t *testing.T) {
|
||||
SetLevel("trace")
|
||||
}
|
||||
|
||||
func TestTrace(t *testing.T) {
|
||||
logger.SetLevel("trace")
|
||||
logger.Trace("trace")
|
||||
logger.SetLevel("off")
|
||||
logger.Trace("trace")
|
||||
}
|
||||
|
||||
func TestTracef(t *testing.T) {
|
||||
logger.SetLevel("trace")
|
||||
logger.Tracef("tracef")
|
||||
logger.SetLevel("off")
|
||||
logger.Tracef("tracef")
|
||||
}
|
||||
|
||||
func TestDebug(t *testing.T) {
|
||||
logger.SetLevel("debug")
|
||||
logger.Debug("debug")
|
||||
logger.SetLevel("off")
|
||||
logger.Debug("debug")
|
||||
}
|
||||
|
||||
func TestDebugf(t *testing.T) {
|
||||
logger.SetLevel("debug")
|
||||
logger.Debugf("debugf")
|
||||
logger.SetLevel("off")
|
||||
logger.Debug("debug")
|
||||
}
|
||||
|
||||
func TestInfo(t *testing.T) {
|
||||
logger.SetLevel("info")
|
||||
logger.Info("info")
|
||||
logger.SetLevel("off")
|
||||
logger.Info("info")
|
||||
}
|
||||
|
||||
func TestInfof(t *testing.T) {
|
||||
logger.SetLevel("info")
|
||||
logger.Infof("infof")
|
||||
logger.SetLevel("off")
|
||||
logger.Infof("infof")
|
||||
}
|
||||
|
||||
func TestWarn(t *testing.T) {
|
||||
logger.SetLevel("warn")
|
||||
logger.Warn("warn")
|
||||
logger.SetLevel("off")
|
||||
logger.Warn("warn")
|
||||
}
|
||||
|
||||
func TestWarnf(t *testing.T) {
|
||||
logger.SetLevel("warn")
|
||||
logger.Warnf("warnf")
|
||||
logger.SetLevel("off")
|
||||
logger.Warnf("warnf")
|
||||
}
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
logger.SetLevel("error")
|
||||
logger.Error("error")
|
||||
logger.SetLevel("off")
|
||||
logger.Error("error")
|
||||
}
|
||||
|
||||
func TestErrorf(t *testing.T) {
|
||||
logger.SetLevel("error")
|
||||
logger.Errorf("errorf")
|
||||
logger.SetLevel("off")
|
||||
logger.Errorf("errorf")
|
||||
}
|
||||
|
||||
func TestGetLevel(t *testing.T) {
|
||||
if getLevel("trace") != Trace {
|
||||
t.FailNow()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if getLevel("debug") != Debug {
|
||||
t.FailNow()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if getLevel("info") != Info {
|
||||
t.FailNow()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if getLevel("warn") != Warn {
|
||||
t.FailNow()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if getLevel("error") != Error {
|
||||
t.FailNow()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoggerSetLevel(t *testing.T) {
|
||||
logger.SetLevel("trace")
|
||||
|
||||
if logger.level != Trace {
|
||||
t.FailNow()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsTraceEnabled(t *testing.T) {
|
||||
logger.SetLevel("trace")
|
||||
|
||||
if !logger.IsTraceEnabled() {
|
||||
t.FailNow()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsDebugEnabled(t *testing.T) {
|
||||
logger.SetLevel("debug")
|
||||
|
||||
if !logger.IsDebugEnabled() {
|
||||
t.FailNow()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsWarnEnabled(t *testing.T) {
|
||||
logger.SetLevel("warn")
|
||||
|
||||
if !logger.IsWarnEnabled() {
|
||||
t.FailNow()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
52
main.go
52
main.go
|
@ -29,21 +29,20 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/editor"
|
||||
"github.com/b3log/wide/event"
|
||||
"github.com/b3log/wide/file"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/notification"
|
||||
"github.com/b3log/wide/output"
|
||||
"github.com/b3log/wide/playground"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/editor"
|
||||
"github.com/88250/wide/event"
|
||||
"github.com/88250/wide/file"
|
||||
"github.com/88250/wide/i18n"
|
||||
"github.com/88250/wide/notification"
|
||||
"github.com/88250/wide/output"
|
||||
"github.com/88250/wide/playground"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// Logger
|
||||
var logger *log.Logger
|
||||
var logger *gulu.Logger
|
||||
|
||||
// The only one init function in Wide.
|
||||
func init() {
|
||||
|
@ -51,13 +50,15 @@ func init() {
|
|||
confData := flag.String("data", "", "path of data dir")
|
||||
confServer := flag.String("server", "", "this will overwrite Wide.Server if specified")
|
||||
confLogLevel := flag.String("log_level", "", "this will overwrite Wide.LogLevel if specified")
|
||||
confReadOnly := flag.String("readonly", "", "this will overrite Wide.ReadOnly if specified")
|
||||
confSiteStatCode := flag.String("site_stat_code", "", "this will overrite Wide.SiteStatCode if specified")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
log.SetLevel("warn")
|
||||
logger = log.NewLogger(os.Stdout)
|
||||
gulu.Log.SetLevel("warn")
|
||||
logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
//wd := util.OS.Pwd()
|
||||
//wd := gulu.OS.Pwd()
|
||||
//if strings.HasPrefix(wd, os.TempDir()) {
|
||||
// logger.Error("Don't run Wide in OS' temp directory or with `go run`")
|
||||
//
|
||||
|
@ -66,14 +67,14 @@ func init() {
|
|||
|
||||
i18n.Load()
|
||||
event.Load()
|
||||
conf.Load(*confPath, *confData, *confServer, *confLogLevel)
|
||||
conf.Load(*confPath, *confData, *confServer, *confLogLevel, *confReadOnly, template.HTML(*confSiteStatCode))
|
||||
|
||||
conf.FixedTimeCheckEnv()
|
||||
session.FixedTimeSave()
|
||||
session.FixedTimeRelease()
|
||||
session.FixedTimeReport()
|
||||
|
||||
logger.Debug("host ["+runtime.Version()+", "+runtime.GOOS+"_"+runtime.GOARCH+"], cross-compilation ", util.Go.GetCrossPlatforms())
|
||||
logger.Debug("host [" + runtime.Version() + ", " + runtime.GOOS + "_" + runtime.GOARCH + "]")
|
||||
}
|
||||
|
||||
// Main.
|
||||
|
@ -93,8 +94,8 @@ func main() {
|
|||
serveSingle("/favicon.ico", "./static/images/favicon.png")
|
||||
|
||||
// oauth
|
||||
http.HandleFunc("/oauth/github/redirect", session.RedirectGitHubHandler)
|
||||
http.HandleFunc("/oauth/github/callback", session.GithubCallbackHandler)
|
||||
http.HandleFunc("/login/redirect", session.LoginRedirectHandler)
|
||||
http.HandleFunc("/login/callback", session.LoginCallbackHandler)
|
||||
|
||||
// session
|
||||
http.HandleFunc("/session/ws", handlerWrapper(session.WSHandler))
|
||||
|
@ -106,7 +107,6 @@ func main() {
|
|||
http.HandleFunc("/stop", handlerWrapper(output.StopHandler))
|
||||
http.HandleFunc("/go/test", handlerWrapper(output.GoTestHandler))
|
||||
http.HandleFunc("/go/vet", handlerWrapper(output.GoVetHandler))
|
||||
http.HandleFunc("/go/mod", handlerWrapper(output.GoModHandler))
|
||||
http.HandleFunc("/go/install", handlerWrapper(output.GoInstallHandler))
|
||||
http.HandleFunc("/output/ws", handlerWrapper(output.WSHandler))
|
||||
|
||||
|
@ -132,7 +132,6 @@ func main() {
|
|||
http.HandleFunc("/file/zip", handlerWrapper(file.GetZipHandler))
|
||||
|
||||
// editor
|
||||
http.HandleFunc("/editor/ws", handlerWrapper(editor.WSHandler))
|
||||
http.HandleFunc("/go/fmt", handlerWrapper(editor.GoFmtHandler))
|
||||
http.HandleFunc("/autocomplete", handlerWrapper(editor.AutocompleteHandler))
|
||||
http.HandleFunc("/exprinfo", handlerWrapper(editor.GetExprInfoHandler))
|
||||
|
@ -159,7 +158,7 @@ func main() {
|
|||
|
||||
logger.Infof("Wide is running [%s]", conf.Wide.Server)
|
||||
|
||||
err := http.ListenAndServe("127.0.0.1:7070", nil)
|
||||
err := http.ListenAndServe("0.0.0.0:7070", nil)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
|
@ -204,7 +203,7 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
|
|||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale,
|
||||
"uid": uid, "sid": session.WideSessions.GenId(), "latestSessionContent": user.LatestSessionContent,
|
||||
"pathSeparator": conf.PathSeparator, "codeMirrorVer": conf.CodeMirrorVer,
|
||||
"user": user, "editorThemes": conf.GetEditorThemes(), "crossPlatforms": util.Go.GetCrossPlatforms()}
|
||||
"user": user, "editorThemes": conf.GetEditorThemes(), "crossPlatforms": []string{"darwin_amd64", "linux_amd64", "windows_amd64"}}
|
||||
|
||||
logger.Debugf("User [%s] has [%d] sessions", uid, len(wideSessions))
|
||||
|
||||
|
@ -255,7 +254,8 @@ func startHandler(w http.ResponseWriter, r *http.Request) {
|
|||
httpSession.Save(r, w)
|
||||
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
user := conf.GetUser(uid)
|
||||
locale := user.Locale
|
||||
userWorkspace := conf.GetUserWorkspace(uid)
|
||||
|
||||
sid := r.URL.Query()["sid"][0]
|
||||
|
@ -265,7 +265,7 @@ func startHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale,
|
||||
"uid": uid, "workspace": userWorkspace, "ver": conf.WideVersion, "sid": sid}
|
||||
"uid": uid, "workspace": userWorkspace, "ver": conf.WideVersion, "sid": sid, "username": user.Name}
|
||||
|
||||
t, err := template.ParseFiles("views/start.html")
|
||||
|
||||
|
@ -409,7 +409,7 @@ func stopwatch(handler func(w http.ResponseWriter, r *http.Request)) func(w http
|
|||
// panicRecover wraps the panic recover process.
|
||||
func panicRecover(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
handler(w, r)
|
||||
}
|
||||
|
|
|
@ -21,12 +21,12 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/event"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/event"
|
||||
"github.com/88250/wide/i18n"
|
||||
"github.com/88250/wide/session"
|
||||
"github.com/88250/wide/util"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
|
@ -40,7 +40,7 @@ const (
|
|||
)
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
// Notification represents a notification.
|
||||
type Notification struct {
|
||||
|
|
145
output/build.go
145
output/build.go
|
@ -27,16 +27,22 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/i18n"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// BuildHandler handles request of building.
|
||||
func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
if conf.Wide.ReadOnly {
|
||||
result.Code = -1
|
||||
result.Msg = "readonly mode"
|
||||
return
|
||||
}
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
|
@ -49,85 +55,40 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
locale := user.Locale
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
sid := args["sid"].(string)
|
||||
|
||||
filePath := args["file"].(string)
|
||||
|
||||
if util.Go.IsAPI(filePath) || !session.CanAccess(uid, filePath) {
|
||||
if gulu.Go.IsAPI(filePath) || !session.CanAccess(uid, filePath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
curDir := filepath.Dir(filePath)
|
||||
|
||||
fout, err := os.Create(filePath)
|
||||
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
code := args["code"].(string)
|
||||
|
||||
fout.WriteString(code)
|
||||
|
||||
if err := fout.Close(); nil != err {
|
||||
if _, err := fout.WriteString(code); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
suffix := ""
|
||||
if util.OS.IsWindows() {
|
||||
suffix = ".exe"
|
||||
}
|
||||
|
||||
goBuildArgs := []string{}
|
||||
goBuildArgs = append(goBuildArgs, "build", "-i")
|
||||
goBuildArgs = append(goBuildArgs, user.BuildArgs(runtime.GOOS)...)
|
||||
|
||||
cmd := exec.Command("go", goBuildArgs...)
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
executable := filepath.Base(curDir) + suffix
|
||||
executable = filepath.Join(curDir, executable)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Succ {
|
||||
return
|
||||
}
|
||||
fout.Close()
|
||||
|
||||
channelRet := map[string]interface{}{}
|
||||
|
||||
if nil != session.OutputWS[sid] {
|
||||
// display "START [go build]" in front-end browser
|
||||
|
||||
|
@ -138,19 +99,69 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
channelRet["cmd"] = "start-build"
|
||||
|
||||
wsChannel := session.OutputWS[sid]
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
|
||||
var goModCmd *exec.Cmd
|
||||
if !gulu.File.IsExist(filepath.Join(curDir, "go.mod")) {
|
||||
curDirName := filepath.Base(curDir)
|
||||
goModCmd = exec.Command("go", "mod", "init", curDirName)
|
||||
} else {
|
||||
goModCmd = exec.Command("go", "mod", "tidy")
|
||||
}
|
||||
goModCmd.Dir = curDir
|
||||
setCmdEnv(goModCmd, uid)
|
||||
outputBytes, err := goModCmd.CombinedOutput()
|
||||
output := string(outputBytes)
|
||||
if nil != err && strings.Contains(output, "go.mod already exists") {
|
||||
logger.Error(err.Error() + ": " + output)
|
||||
result.Code = -1
|
||||
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
var goBuildArgs []string
|
||||
goBuildArgs = append(goBuildArgs, "build")
|
||||
goBuildArgs = append(goBuildArgs, user.BuildArgs(runtime.GOOS)...)
|
||||
//if !gulu.Str.Contains("-i", goBuildArgs) {
|
||||
// goBuildArgs = append(goBuildArgs, "-i")
|
||||
//}
|
||||
|
||||
cmd := exec.Command("go", goBuildArgs...)
|
||||
cmd.Dir = curDir
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
suffix := ""
|
||||
if gulu.OS.IsWindows() {
|
||||
suffix = ".exe"
|
||||
}
|
||||
executable := filepath.Base(curDir) + suffix
|
||||
executable = filepath.Join(curDir, executable)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if 0 != result.Code {
|
||||
return
|
||||
}
|
||||
|
||||
if err := cmd.Start(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -162,7 +173,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
/////////
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
for {
|
||||
wsChannel := session.OutputWS[sid]
|
||||
|
@ -175,8 +186,14 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
break
|
||||
}
|
||||
|
||||
_, ok := err.(*os.PathError)
|
||||
if ok {
|
||||
// 构建时报 “read |0: file already closed” https://github.com/b3log/wide/issues/363
|
||||
break
|
||||
}
|
||||
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
logger.Warnf("%#v", err)
|
||||
|
||||
break
|
||||
}
|
||||
|
|
|
@ -26,16 +26,22 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/i18n"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// CrossCompilationHandler handles request of cross compilation.
|
||||
func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
if conf.Wide.ReadOnly {
|
||||
result.Code = -1
|
||||
result.Msg = "readonly mode"
|
||||
return
|
||||
}
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
|
@ -50,7 +56,7 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -58,7 +64,7 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sid := args["sid"].(string)
|
||||
filePath := args["path"].(string)
|
||||
|
||||
if util.Go.IsAPI(filePath) || !session.CanAccess(uid, filePath) {
|
||||
if gulu.Go.IsAPI(filePath) || !session.CanAccess(uid, filePath) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
|
@ -106,7 +112,7 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -114,12 +120,12 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
stderr, err := cmd.StderrPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Succ {
|
||||
if 0 != result.Code {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -146,13 +152,13 @@ func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := cmd.Start(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
defer cmd.Wait()
|
||||
|
||||
// read all
|
||||
|
|
|
@ -26,16 +26,22 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/i18n"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// GoInstallHandler handles request of go install.
|
||||
func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
if conf.Wide.ReadOnly {
|
||||
result.Code = -1
|
||||
result.Msg = "readonly mode"
|
||||
return
|
||||
}
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
|
@ -50,7 +56,7 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -70,7 +76,7 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
|
|||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -78,12 +84,12 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
|
|||
stderr, err := cmd.StderrPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Succ {
|
||||
if 0 != result.Code {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -110,13 +116,13 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := cmd.Start(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
defer cmd.Wait()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [go install] [id=%d, dir=%s]", uid, sid, runningId, curDir)
|
||||
|
|
136
output/mod.go
136
output/mod.go
|
@ -1,136 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package output
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
)
|
||||
|
||||
// GoModHandler handles request of go mod.
|
||||
func GoModHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
|
||||
return
|
||||
}
|
||||
uid := httpSession.Values["uid"].(string)
|
||||
locale := conf.GetUser(uid).Locale
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
sid := args["sid"].(string)
|
||||
|
||||
filePath := args["file"].(string)
|
||||
curDir := filepath.Dir(filePath)
|
||||
curDirName := filepath.Base(curDir)
|
||||
|
||||
cmd := exec.Command("go", "mod", "init", curDirName)
|
||||
cmd.Dir = curDir
|
||||
|
||||
setCmdEnv(cmd, uid)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Succ {
|
||||
return
|
||||
}
|
||||
|
||||
channelRet := map[string]interface{}{}
|
||||
|
||||
if nil != session.OutputWS[sid] {
|
||||
// display "START [go mod]" in front-end browser
|
||||
|
||||
channelRet["output"] = "<span class='start-mod'>" + i18n.Get(locale, "start-mod").(string) + "</span>\n"
|
||||
channelRet["cmd"] = "start-mod"
|
||||
|
||||
wsChannel := session.OutputWS[sid]
|
||||
|
||||
err := wsChannel.WriteJSON(&channelRet)
|
||||
if nil != err {
|
||||
logger.Warn(err)
|
||||
return
|
||||
}
|
||||
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(io.MultiReader(stdout, stderr))
|
||||
|
||||
if err := cmd.Start(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
runningId := rand.Int()
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [go mod] [runningId=%d]", uid, sid, runningId)
|
||||
channelRet = map[string]interface{}{}
|
||||
channelRet["cmd"] = "go mod"
|
||||
|
||||
buf, _ := ioutil.ReadAll(reader)
|
||||
output := string(buf)
|
||||
err = cmd.Wait()
|
||||
if nil != err || 0 != cmd.ProcessState.ExitCode() {
|
||||
logger.Debugf("User [%s, %s] 's [go mod] [runningId=%d] has done (with error)", uid, sid, runningId)
|
||||
channelRet["output"] = "<span class='mod-error'>" + i18n.Get(locale, "mod-error").(string) + "</span>\n" + output
|
||||
} else {
|
||||
logger.Debugf("User [%s, %s] 's running [go mod] [runningId=%d] has done", uid, sid, runningId)
|
||||
channelRet["output"] = "<span class='mod-succ'>" + i18n.Get(locale, "mod-succ").(string) + "</span>\n" + output
|
||||
}
|
||||
|
||||
wsChannel := session.OutputWS[sid]
|
||||
if nil != wsChannel {
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
wsChannel.Refresh()
|
||||
}
|
||||
}
|
|
@ -25,10 +25,10 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/session"
|
||||
"github.com/88250/wide/util"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
|
@ -38,7 +38,7 @@ const (
|
|||
)
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
// Lint represents a code lint.
|
||||
type Lint struct {
|
||||
|
@ -122,7 +122,7 @@ func setCmdEnv(cmd *exec.Cmd, uid string) {
|
|||
"GOCACHE="+cache,
|
||||
"PATH="+os.Getenv("PATH"))
|
||||
|
||||
if util.OS.IsWindows() {
|
||||
if gulu.OS.IsWindows() {
|
||||
// FIXME: for some weird issues on Windows, such as: The requested service provider could not be loaded or initialized.
|
||||
cmd.Env = append(cmd.Env, os.Environ()...)
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
package output
|
||||
|
||||
import (
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/88250/wide/session"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
|
|
@ -24,16 +24,16 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/i18n"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// GoTestHandler handles request of go test.
|
||||
func GoTestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
|
@ -48,7 +48,7 @@ func GoTestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ func GoTestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -74,12 +74,12 @@ func GoTestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
stderr, err := cmd.StderrPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Succ {
|
||||
if 0 != result.Code {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -106,13 +106,13 @@ func GoTestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := cmd.Start(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [go test] [runningId=%d]", uid, sid, runningId)
|
||||
|
||||
|
|
|
@ -24,16 +24,16 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/i18n"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// GoVetHandler handles request of go vet.
|
||||
func GoVetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
|
@ -48,7 +48,7 @@ func GoVetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ func GoVetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -74,12 +74,12 @@ func GoVetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
stderr, err := cmd.StderrPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Succ {
|
||||
if 0 != result.Code {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -106,13 +106,13 @@ func GoVetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := cmd.Start(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
go func(runningId int) {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
logger.Debugf("User [%s, %s] is running [go vet] [runningId=%d]", uid, sid, runningId)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "wide",
|
||||
"version": "1.4.0",
|
||||
"version": "1.6.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -36,15 +36,9 @@
|
|||
}
|
||||
},
|
||||
"acorn": {
|
||||
"version": "5.7.3",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
|
||||
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
|
||||
"dev": true
|
||||
},
|
||||
"amdefine": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
||||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
|
||||
"version": "5.7.4",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
|
||||
"integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-colors": {
|
||||
|
@ -71,12 +65,6 @@
|
|||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-wrap": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
|
||||
|
@ -144,12 +132,6 @@
|
|||
"integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
|
||||
"dev": true
|
||||
},
|
||||
"array-differ": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
|
||||
"integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=",
|
||||
"dev": true
|
||||
},
|
||||
"array-each": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
|
||||
|
@ -216,12 +198,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"array-uniq": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
|
||||
"integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
|
||||
"dev": true
|
||||
},
|
||||
"array-unique": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
|
||||
|
@ -345,12 +321,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"beeper": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
|
||||
"integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=",
|
||||
"dev": true
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
|
||||
|
@ -408,41 +378,6 @@
|
|||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"dev": true
|
||||
},
|
||||
"bufferstreams": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/bufferstreams/-/bufferstreams-1.0.1.tgz",
|
||||
"integrity": "sha1-z7GtlWjTujz+k1upq92VLeiKqyo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"readable-stream": "^1.0.33"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
|
||||
"dev": true
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.1",
|
||||
"isarray": "0.0.1",
|
||||
"string_decoder": "~0.10.x"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"cache-base": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
|
||||
|
@ -466,19 +401,6 @@
|
|||
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^2.2.1",
|
||||
"escape-string-regexp": "^1.0.2",
|
||||
"has-ansi": "^2.0.0",
|
||||
"strip-ansi": "^3.0.0",
|
||||
"supports-color": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz",
|
||||
|
@ -530,27 +452,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"clean-css": {
|
||||
"version": "3.4.28",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz",
|
||||
"integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "2.8.x",
|
||||
"source-map": "0.4.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
||||
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"amdefine": ">=0.0.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
|
||||
|
@ -632,15 +533,6 @@
|
|||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
|
||||
"dev": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
|
||||
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-readlink": ">= 1.0.0"
|
||||
}
|
||||
},
|
||||
"component-emitter": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||
|
@ -742,12 +634,6 @@
|
|||
"es5-ext": "^0.10.9"
|
||||
}
|
||||
},
|
||||
"dateformat": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
|
||||
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
|
@ -882,41 +768,6 @@
|
|||
"integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=",
|
||||
"dev": true
|
||||
},
|
||||
"duplexer2": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
|
||||
"integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"readable-stream": "~1.1.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
|
||||
"dev": true
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.1",
|
||||
"isarray": "0.0.1",
|
||||
"string_decoder": "~0.10.x"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"duplexify": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
|
||||
|
@ -1001,12 +852,6 @@
|
|||
"es6-symbol": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"event-emitter": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
|
||||
|
@ -1950,12 +1795,6 @@
|
|||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
|
||||
"dev": true
|
||||
},
|
||||
"graceful-readlink": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
|
||||
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
|
||||
"dev": true
|
||||
},
|
||||
"gulp": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz",
|
||||
|
@ -1996,6 +1835,44 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"gulp-clean-css": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.2.0.tgz",
|
||||
"integrity": "sha512-r4zQsSOAK2UYUL/ipkAVCTRg/2CLZ2A+oPVORopBximRksJ6qy3EX1KGrIWT4ZrHxz3Hlobb1yyJtqiut7DNjA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clean-css": "4.2.1",
|
||||
"plugin-error": "1.0.1",
|
||||
"through2": "3.0.1",
|
||||
"vinyl-sourcemaps-apply": "0.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"clean-css": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
|
||||
"integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-map": "~0.6.0"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
},
|
||||
"through2": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
|
||||
"integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"readable-stream": "2 || 3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gulp-concat": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz",
|
||||
|
@ -2007,20 +1884,6 @@
|
|||
"vinyl": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"gulp-minify-css": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/gulp-minify-css/-/gulp-minify-css-1.2.4.tgz",
|
||||
"integrity": "sha1-thZJV2Auon+eWtiCJ2ld0gV3jAY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clean-css": "^3.3.3",
|
||||
"gulp-util": "^3.0.5",
|
||||
"object-assign": "^4.0.1",
|
||||
"readable-stream": "^2.0.0",
|
||||
"vinyl-bufferstream": "^1.0.1",
|
||||
"vinyl-sourcemaps-apply": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"gulp-sourcemaps": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz",
|
||||
|
@ -2066,69 +1929,6 @@
|
|||
"vinyl-sourcemaps-apply": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"gulp-util": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
|
||||
"integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-differ": "^1.0.0",
|
||||
"array-uniq": "^1.0.2",
|
||||
"beeper": "^1.0.0",
|
||||
"chalk": "^1.0.0",
|
||||
"dateformat": "^2.0.0",
|
||||
"fancy-log": "^1.1.0",
|
||||
"gulplog": "^1.0.0",
|
||||
"has-gulplog": "^0.1.0",
|
||||
"lodash._reescape": "^3.0.0",
|
||||
"lodash._reevaluate": "^3.0.0",
|
||||
"lodash._reinterpolate": "^3.0.0",
|
||||
"lodash.template": "^3.0.0",
|
||||
"minimist": "^1.1.0",
|
||||
"multipipe": "^0.1.2",
|
||||
"object-assign": "^3.0.0",
|
||||
"replace-ext": "0.0.1",
|
||||
"through2": "^2.0.0",
|
||||
"vinyl": "^0.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"clone": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
|
||||
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
|
||||
"dev": true
|
||||
},
|
||||
"clone-stats": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
|
||||
"integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=",
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
|
||||
"integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=",
|
||||
"dev": true
|
||||
},
|
||||
"replace-ext": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
|
||||
"integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
|
||||
"dev": true
|
||||
},
|
||||
"vinyl": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
|
||||
"integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clone": "^1.0.0",
|
||||
"clone-stats": "^0.0.1",
|
||||
"replace-ext": "0.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gulplog": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
|
||||
|
@ -2138,15 +1938,6 @@
|
|||
"glogg": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"has-ansi": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"has-gulplog": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
|
||||
|
@ -2542,125 +2333,6 @@
|
|||
"strip-bom": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"lodash._basecopy": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
|
||||
"integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._basetostring": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
|
||||
"integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._basevalues": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
|
||||
"integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._getnative": {
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
|
||||
"integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._isiterateecall": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
|
||||
"integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._reescape": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
|
||||
"integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._reevaluate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
|
||||
"integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._reinterpolate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
|
||||
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._root": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
|
||||
"integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.escape": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
|
||||
"integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash._root": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lodash.isarguments": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||
"integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.isarray": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
|
||||
"integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.keys": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
|
||||
"integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash._getnative": "^3.0.0",
|
||||
"lodash.isarguments": "^3.0.0",
|
||||
"lodash.isarray": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lodash.restparam": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
|
||||
"integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.template": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
|
||||
"integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash._basecopy": "^3.0.0",
|
||||
"lodash._basetostring": "^3.0.0",
|
||||
"lodash._basevalues": "^3.0.0",
|
||||
"lodash._isiterateecall": "^3.0.0",
|
||||
"lodash._reinterpolate": "^3.0.0",
|
||||
"lodash.escape": "^3.0.0",
|
||||
"lodash.keys": "^3.0.0",
|
||||
"lodash.restparam": "^3.0.0",
|
||||
"lodash.templatesettings": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lodash.templatesettings": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
|
||||
"integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash._reinterpolate": "^3.0.0",
|
||||
"lodash.escape": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lru-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
|
||||
|
@ -2790,16 +2462,10 @@
|
|||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true
|
||||
},
|
||||
"mixin-deep": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
|
||||
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
|
||||
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"for-in": "^1.0.2",
|
||||
|
@ -2823,15 +2489,6 @@
|
|||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"dev": true
|
||||
},
|
||||
"multipipe": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
|
||||
"integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"duplexer2": "0.0.2"
|
||||
}
|
||||
},
|
||||
"mute-stdout": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
|
||||
|
@ -3144,6 +2801,18 @@
|
|||
"pinkie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"plugin-error": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
|
||||
"integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-colors": "^1.0.1",
|
||||
"arr-diff": "^4.0.0",
|
||||
"arr-union": "^3.1.0",
|
||||
"extend-shallow": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"posix-character-classes": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
|
||||
|
@ -3402,9 +3071,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"set-value": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
|
||||
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
|
||||
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
|
@ -3686,12 +3355,6 @@
|
|||
"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
|
||||
"dev": true
|
||||
},
|
||||
"sver-compat": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz",
|
||||
|
@ -3859,38 +3522,15 @@
|
|||
"dev": true
|
||||
},
|
||||
"union-value": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
|
||||
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
|
||||
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arr-union": "^3.1.0",
|
||||
"get-value": "^2.0.6",
|
||||
"is-extendable": "^0.1.1",
|
||||
"set-value": "^0.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"set-value": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
|
||||
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-extendable": "^0.1.1",
|
||||
"is-plain-object": "^2.0.1",
|
||||
"to-object-path": "^0.3.0"
|
||||
}
|
||||
}
|
||||
"set-value": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"unique-stream": {
|
||||
|
@ -4006,15 +3646,6 @@
|
|||
"replace-ext": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"vinyl-bufferstream": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vinyl-bufferstream/-/vinyl-bufferstream-1.0.1.tgz",
|
||||
"integrity": "sha1-BTeGn1gO/6TKRay0dXnkuf5jCBo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bufferstreams": "1.0.1"
|
||||
}
|
||||
},
|
||||
"vinyl-fs": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
|
||||
|
@ -4129,12 +3760,13 @@
|
|||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
|
||||
"integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz",
|
||||
"integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^3.0.0"
|
||||
"camelcase": "^3.0.0",
|
||||
"object.assign": "^4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
10
package.json
10
package.json
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"name": "wide",
|
||||
"version": "1.4.0",
|
||||
"description": "A Web-based IDE for Teams using Go programming language/Golang.",
|
||||
"version": "1.6.0",
|
||||
"description": "A Web-based Go IDE , do your development anytime, anywhere.",
|
||||
"homepage": "https://wide.b3log.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/b3log/wide.git"
|
||||
"url": "git://github.com/88250/wide.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/b3log/wide/issues"
|
||||
"url": "https://github.com/88250/wide/issues"
|
||||
},
|
||||
"license": "Apache License",
|
||||
"private": true,
|
||||
|
@ -28,8 +28,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-clean-css": "^4.2.0",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-minify-css": "^1.2.4",
|
||||
"gulp-sourcemaps": "^2.6.5",
|
||||
"gulp-uglify": "^3.0.1"
|
||||
}
|
||||
|
|
12
pkg.sh
12
pkg.sh
|
@ -24,7 +24,7 @@ export GOARCH=amd64
|
|||
echo wide-${ver}-${GOOS}-${GOARCH}.tar.gz
|
||||
go build
|
||||
go build github.com/visualfc/gotools
|
||||
go build github.com/nsf/gocode
|
||||
go build github.com/stamblerre/gocode
|
||||
tar zcf ${target}/wide-${ver}-${GOOS}-${GOARCH}.tar.gz ${list} gotools gocode wide --exclude-vcs --exclude='conf/*.go' --exclude='i18n/*.go'
|
||||
rm -f wide gotools gocode
|
||||
|
||||
|
@ -33,7 +33,7 @@ export GOARCH=386
|
|||
echo wide-${ver}-${GOOS}-${GOARCH}.tar.gz
|
||||
go build
|
||||
go build github.com/visualfc/gotools
|
||||
go build github.com/nsf/gocode
|
||||
go build github.com/stamblerre/gocode
|
||||
tar zcf ${target}/wide-${ver}-${GOOS}-${GOARCH}.tar.gz ${list} gotools gocode wide --exclude-vcs --exclude='conf/*.go' --exclude='i18n/*.go'
|
||||
rm -f wide gotools gocode
|
||||
|
||||
|
@ -45,7 +45,7 @@ export GOARCH=amd64
|
|||
echo wide-${ver}-${GOOS}-${GOARCH}.tar.gz
|
||||
go build
|
||||
go build github.com/visualfc/gotools
|
||||
go build github.com/nsf/gocode
|
||||
go build github.com/stamblerre/gocode
|
||||
tar zcf ${target}/wide-${ver}-${GOOS}-${GOARCH}.tar.gz ${list} gotools gocode wide --exclude-vcs --exclude='conf/*.go' --exclude='i18n/*.go'
|
||||
rm -f wide gotools gocode
|
||||
|
||||
|
@ -54,7 +54,7 @@ export GOARCH=386
|
|||
echo wide-${ver}-${GOOS}-${GOARCH}.tar.gz
|
||||
go build
|
||||
go build github.com/visualfc/gotools
|
||||
go build github.com/nsf/gocode
|
||||
go build github.com/stamblerre/gocode
|
||||
tar zcf ${target}/wide-${ver}-${GOOS}-${GOARCH}.tar.gz ${list} gotools gocode wide --exclude-vcs --exclude='conf/*.go' --exclude='i18n/*.go'
|
||||
rm -f wide gotools gocode
|
||||
|
||||
|
@ -66,7 +66,7 @@ export GOARCH=amd64
|
|||
echo wide-${ver}-${GOOS}-${GOARCH}.zip
|
||||
go build
|
||||
go build github.com/visualfc/gotools
|
||||
go build github.com/nsf/gocode
|
||||
go build github.com/stamblerre/gocode
|
||||
zip -r -q ${target}/wide-${ver}-${GOOS}-${GOARCH}.zip ${list} gotools.exe gocode.exe wide.exe --exclude=conf/*.go --exclude=i18n/*.go
|
||||
rm -f wide.exe gotools.exe gocode.exe
|
||||
|
||||
|
@ -75,6 +75,6 @@ export GOARCH=386
|
|||
echo wide-${ver}-${GOOS}-${GOARCH}.zip
|
||||
go build
|
||||
go build github.com/visualfc/gotools
|
||||
go build github.com/nsf/gocode
|
||||
go build github.com/stamblerre/gocode
|
||||
zip -r -q ${target}/wide-${ver}-${GOOS}-${GOARCH}.zip ${list} gotools.exe gocode.exe wide.exe --exclude=conf/*.go --exclude=i18n/*.go
|
||||
rm -f wide.exe gotools.exe gocode.exe
|
||||
|
|
|
@ -18,18 +18,24 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// AutocompleteHandler handles request of code autocompletion.
|
||||
func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var args map[string]interface{}
|
||||
if conf.Wide.ReadOnly {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
@ -48,16 +54,24 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
line := int(args["cursorLine"].(float64))
|
||||
ch := int(args["cursorCh"].(float64))
|
||||
|
||||
file, err := os.Create("wide_autocomplete_" + gulu.Rand.String(16) + ".go")
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
file.WriteString(code)
|
||||
file.Close()
|
||||
|
||||
path := file.Name()
|
||||
defer os.Remove(path)
|
||||
|
||||
offset := getCursorOffset(code, line, ch)
|
||||
|
||||
argv := []string{"-f=json", "autocomplete", strconv.Itoa(offset)}
|
||||
gocode := util.Go.GetExecutableInGOBIN("gocode")
|
||||
argv := []string{"-f=json", "--in=" + path, "autocomplete", strconv.Itoa(offset)}
|
||||
gocode := gulu.Go.GetExecutableInGOBIN("gocode")
|
||||
cmd := exec.Command(gocode, argv...)
|
||||
|
||||
stdin, _ := cmd.StdinPipe()
|
||||
stdin.Write([]byte(code))
|
||||
stdin.Close()
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
|
|
|
@ -22,15 +22,21 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// BuildHandler handles request of Playground building.
|
||||
func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
if conf.Wide.ReadOnly {
|
||||
result.Code = -1
|
||||
result.Msg = "readonly mode"
|
||||
return
|
||||
}
|
||||
|
||||
httpSession, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if httpSession.IsNew {
|
||||
|
@ -42,7 +48,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -51,7 +57,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
filePath := filepath.Clean(conf.Wide.Data + "/playground/" + fileName)
|
||||
|
||||
suffix := ""
|
||||
if util.OS.IsWindows() {
|
||||
if gulu.OS.IsWindows() {
|
||||
suffix = ".exe"
|
||||
}
|
||||
|
||||
|
@ -66,7 +72,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
|
|||
data["output"] = template.HTML(string(out))
|
||||
|
||||
if nil != err {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -24,15 +24,21 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/session"
|
||||
)
|
||||
|
||||
// SaveHandler handles request of Playground code save.
|
||||
func SaveHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
if conf.Wide.ReadOnly {
|
||||
result.Code = -1
|
||||
result.Msg = "readonly mode"
|
||||
return
|
||||
}
|
||||
|
||||
session, _ := session.HTTPSession.Get(r, session.CookieName)
|
||||
if session.IsNew {
|
||||
|
@ -44,7 +50,7 @@ func SaveHandler(w http.ResponseWriter, r *http.Request) {
|
|||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -57,7 +63,7 @@ func SaveHandler(w http.ResponseWriter, r *http.Request) {
|
|||
stdin, err := cmd.StdinPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -89,7 +95,7 @@ func SaveHandler(w http.ResponseWriter, r *http.Request) {
|
|||
fout.WriteString(code)
|
||||
if err := fout.Close(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -26,16 +26,16 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/i18n"
|
||||
"github.com/88250/wide/session"
|
||||
"github.com/88250/wide/util"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
// IndexHandler handles request of Playground index.
|
||||
func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -55,11 +55,11 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// try to load file
|
||||
code := conf.HelloWorld
|
||||
fileName := "8b7cc38b4c12e6fde5c4d15a4f2f32e5.go" // MD5 of HelloWorld.go
|
||||
fileName := "6c5595ec6fbadf4cfce3edbfcfd8c6d0.go" // MD5 of HelloWorld.go
|
||||
|
||||
if strings.HasSuffix(r.URL.Path, ".go") {
|
||||
fileNameArg := r.URL.Path[len("/playground/"):]
|
||||
filePath := filepath.Clean(conf.Wide.Data+ "/playground/" + fileNameArg)
|
||||
filePath := filepath.Clean(conf.Wide.Data + "/playground/" + fileNameArg)
|
||||
|
||||
bytes, err := ioutil.ReadFile(filePath)
|
||||
if nil != err {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
package playground
|
||||
|
||||
import (
|
||||
"github.com/b3log/wide/session"
|
||||
"github.com/88250/wide/session"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
|
108
session/oauth.go
108
session/oauth.go
|
@ -15,7 +15,7 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
|
@ -25,45 +25,26 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/i18n"
|
||||
"github.com/88250/wide/util"
|
||||
)
|
||||
|
||||
var states = map[string]string{}
|
||||
|
||||
// RedirectGitHubHandler redirects to GitHub auth page.
|
||||
func RedirectGitHubHandler(w http.ResponseWriter, r *http.Request) {
|
||||
requestResult := util.NewResult()
|
||||
_, _, errs := gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
|
||||
Get("https://hacpai.com/oauth/wide/client").
|
||||
Set("user-agent", conf.UserAgent).Timeout(10 * time.Second).EndStruct(requestResult)
|
||||
if nil != errs {
|
||||
logger.Errorf("Get oauth client id failed: %+v", errs)
|
||||
http.Error(w, "Get oauth info failed", http.StatusInternalServerError)
|
||||
// LoginRedirectHandler redirects to HacPai auth page.
|
||||
func LoginRedirectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
loginAuthURL := conf.Wide.OAuthLoginURL + "?response_type=code&redirect_uri=" + conf.Wide.Server + "/login/callback"
|
||||
|
||||
return
|
||||
}
|
||||
if 0 != requestResult.Code {
|
||||
logger.Errorf("get oauth client id failed [code=%d, msg=%s]", requestResult.Code, requestResult.Msg)
|
||||
http.Error(w, "Get oauth info failed", http.StatusNotFound)
|
||||
|
||||
return
|
||||
}
|
||||
data := requestResult.Data.(map[string]interface{})
|
||||
clientId := data["clientId"].(string)
|
||||
loginAuthURL := data["loginAuthURL"].(string)
|
||||
|
||||
state := r.URL.Query().Get("state")
|
||||
referer := conf.Wide.Server + "__" + state
|
||||
state = util.Rand.String(16) + referer
|
||||
// надо будет добавить ttlcache для state и проверять для предотвращения атак CSRF
|
||||
state := gulu.Rand.String(16)
|
||||
states[state] = state
|
||||
path := loginAuthURL + "?client_id=" + clientId + "&state=" + state + "&scope=public_repo,read:user,user:follow"
|
||||
path := loginAuthURL + "&state=" + state + "&client_id=" + conf.Wide.OAuthClientID
|
||||
http.Redirect(w, r, path, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func GithubCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func LoginCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||
state := r.URL.Query().Get("state")
|
||||
if _, exist := states[state]; !exist {
|
||||
http.Error(w, "Get state param failed", http.StatusBadRequest)
|
||||
|
@ -72,31 +53,37 @@ func GithubCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
delete(states, state)
|
||||
|
||||
referer := state[16:]
|
||||
if strings.Contains(referer, "__0") || strings.Contains(referer, "__1") {
|
||||
referer = referer[:len(referer)-len("__0")]
|
||||
}
|
||||
accessToken := r.URL.Query().Get("ak")
|
||||
githubUser := GitHubUserInfo(accessToken)
|
||||
if nil == githubUser {
|
||||
logger.Warnf("Can not get user info with token [" + accessToken + "]")
|
||||
http.Error(w, "Get user info failed", http.StatusUnauthorized)
|
||||
code := r.URL.Query().Get("code")
|
||||
accessToken, err := util.GetOAuthToken(
|
||||
conf.Wide.OAuthAccessTokenURL,
|
||||
conf.Wide.OAuthClientID,
|
||||
conf.Wide.OAuthClientSecret,
|
||||
code,
|
||||
conf.Wide.Server+`/login/callback`)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf(`get access_token failed. error: %s`, err.Error()), http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
githubId := githubUser["userId"].(string)
|
||||
userName := githubUser["userName"].(string)
|
||||
avatar := githubUser["userAvatarURL"].(string)
|
||||
userInfo, err := util.OpenIdUserInfo(conf.Wide.OAuthUserInfoURL, accessToken)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf(`get user_info failed. error: %s`, err.Error()), http.StatusBadRequest)
|
||||
|
||||
user := conf.GetUser(githubId)
|
||||
return
|
||||
}
|
||||
|
||||
userId := userInfo["userId"].(string)
|
||||
userName := userInfo["userName"].(string)
|
||||
avatar := userInfo["avatar"].(string)
|
||||
user := conf.GetUser(userId)
|
||||
if nil == user {
|
||||
msg := addUser(githubId, userName, avatar)
|
||||
msg := addUser(userId, userName, avatar)
|
||||
if userCreated != msg {
|
||||
result := util.NewResult()
|
||||
result.Succ = false
|
||||
result := gulu.Ret.NewResult()
|
||||
result.Code = -1
|
||||
result.Msg = msg
|
||||
util.RetResult(w, r, result)
|
||||
gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -104,7 +91,7 @@ func GithubCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// create a HTTP session
|
||||
httpSession, _ := HTTPSession.Get(r, CookieName)
|
||||
httpSession.Values["uid"] = githubId
|
||||
httpSession.Values["uid"] = userId
|
||||
httpSession.Values["id"] = strconv.Itoa(rand.Int())
|
||||
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
|
||||
httpSession.Save(r, w)
|
||||
|
@ -112,25 +99,6 @@ func GithubCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// GitHubUserInfo returns GitHub user info specified by the given access token.
|
||||
func GitHubUserInfo(accessToken string) (ret map[string]interface{}) {
|
||||
result := map[string]interface{}{}
|
||||
response, data, errors := gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
|
||||
Get("https://hacpai.com/github/user?ak="+accessToken).Timeout(7*time.Second).
|
||||
Set("User-Agent", conf.UserAgent).EndStruct(&result)
|
||||
if nil != errors || http.StatusOK != response.StatusCode {
|
||||
logger.Errorf("Get github user info failed: %+v, %s", errors, data)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if 0 != result["sc"].(float64) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return result["data"].(map[string]interface{})
|
||||
}
|
||||
|
||||
// LoginHandler handles request of show login page.
|
||||
func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(conf.Wide.Locale),
|
||||
|
@ -149,8 +117,8 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// LogoutHandler handles request of user logout (exit).
|
||||
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
httpSession, _ := HTTPSession.Get(r, CookieName)
|
||||
|
||||
|
|
|
@ -15,10 +15,8 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/util"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -28,6 +26,10 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/util"
|
||||
)
|
||||
|
||||
// Type of process set.
|
||||
|
@ -43,20 +45,26 @@ var procMutex sync.Mutex
|
|||
|
||||
// RunHandler handles request of executing a binary file.
|
||||
func RunHandler(w http.ResponseWriter, r *http.Request, channel map[string]*util.WSChannel) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
if conf.Wide.ReadOnly {
|
||||
result.Code = -1
|
||||
result.Msg = "readonly mode"
|
||||
return
|
||||
}
|
||||
|
||||
var args map[string]interface{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
}
|
||||
|
||||
sid := args["sid"].(string)
|
||||
wSession := WideSessions.Get(sid)
|
||||
if nil == wSession {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
}
|
||||
|
||||
filePath := args["executable"].(string)
|
||||
|
@ -66,35 +74,27 @@ func RunHandler(w http.ResponseWriter, r *http.Request, channel map[string]*util
|
|||
var cmd *exec.Cmd
|
||||
if conf.Docker {
|
||||
fileName := filepath.Base(filePath)
|
||||
cmd = exec.Command("docker", "run", "--rm", "--cpus", "0.05", "--name", rid, "-v", filePath+":/"+fileName, conf.DockerImageGo, "/"+fileName)
|
||||
cmd = exec.Command("docker", "run", "--rm", "--name", rid, "-v", filePath+":/"+fileName,
|
||||
"--memory", "64M", "--cpus", "0.1",
|
||||
conf.DockerImageGo, "/"+fileName)
|
||||
} else {
|
||||
cmd = exec.Command(filePath)
|
||||
curDir := filepath.Dir(filePath)
|
||||
cmd.Dir = curDir
|
||||
}
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
}
|
||||
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
}
|
||||
|
||||
outReader := bufio.NewReader(stdout)
|
||||
errReader := bufio.NewReader(stderr)
|
||||
outBuf := &bytes.Buffer{}
|
||||
errBuf := &bytes.Buffer{}
|
||||
cmd.Stdout = outBuf
|
||||
cmd.Stderr = errBuf
|
||||
|
||||
if err := cmd.Start(); nil != err {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
}
|
||||
wsChannel := channel[sid]
|
||||
channelRet := map[string]interface{}{}
|
||||
if !result.Succ {
|
||||
if 0 != result.Code {
|
||||
channelRet["cmd"] = "run-done"
|
||||
channelRet["output"] = ""
|
||||
wsChannel.WriteJSON(&channelRet)
|
||||
|
@ -108,6 +108,7 @@ func RunHandler(w http.ResponseWriter, r *http.Request, channel map[string]*util
|
|||
|
||||
channelRet["pid"] = cmd.Process.Pid
|
||||
Processes.Add(wSession, cmd.Process)
|
||||
shouldExitBuf := false
|
||||
|
||||
// push once for front-end to get the 'run' state and pid
|
||||
if nil != wsChannel {
|
||||
|
@ -120,19 +121,27 @@ func RunHandler(w http.ResponseWriter, r *http.Request, channel map[string]*util
|
|||
}
|
||||
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
|
||||
defer gulu.Panic.Recover(nil)
|
||||
logger.Debugf("User [%s, %s] is running [id=%s, file=%s]", wSession.UserId, sid, rid, filePath)
|
||||
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
|
||||
defer gulu.Panic.Recover(nil)
|
||||
for {
|
||||
r, _, err := outReader.ReadRune()
|
||||
if nil != err {
|
||||
if shouldExitBuf {
|
||||
break
|
||||
}
|
||||
|
||||
if 1 > outBuf.Len() {
|
||||
time.Sleep(7 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
r, _, err := outBuf.ReadRune()
|
||||
if nil != err {
|
||||
time.Sleep(7 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
oneRuneStr := string(r)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, "<", "<", -1)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, ">", ">", -1)
|
||||
|
@ -147,11 +156,21 @@ func RunHandler(w http.ResponseWriter, r *http.Request, channel map[string]*util
|
|||
}()
|
||||
|
||||
for {
|
||||
r, _, err := errReader.ReadRune()
|
||||
if nil != err {
|
||||
if shouldExitBuf {
|
||||
break
|
||||
}
|
||||
|
||||
if 1 > errBuf.Len() {
|
||||
time.Sleep(7 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
r, _, err := errBuf.ReadRune()
|
||||
if nil != err {
|
||||
time.Sleep(7 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
oneRuneStr := string(r)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, "<", "<", -1)
|
||||
oneRuneStr = strings.Replace(oneRuneStr, ">", ">", -1)
|
||||
|
@ -184,6 +203,7 @@ func RunHandler(w http.ResponseWriter, r *http.Request, channel map[string]*util
|
|||
channelRet["output"] = "\n<span class='stderr'>run program complete</span>\n"
|
||||
}
|
||||
|
||||
shouldExitBuf = true
|
||||
Processes.Remove(wSession, cmd.Process)
|
||||
logger.Debugf("User [%s, %s] done running [id=%s, file=%s, kill=%v]", wSession.UserId, sid, rid, filePath, kill)
|
||||
|
||||
|
@ -196,13 +216,13 @@ func RunHandler(w http.ResponseWriter, r *http.Request, channel map[string]*util
|
|||
|
||||
// StopHandler handles request of stopping a running process.
|
||||
func StopHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
var args map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -212,7 +232,7 @@ func StopHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
wSession := WideSessions.Get(sid)
|
||||
if nil == wSession {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -35,10 +35,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/event"
|
||||
"github.com/b3log/wide/log"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/event"
|
||||
"github.com/88250/wide/util"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/gorilla/websocket"
|
||||
|
@ -52,7 +52,7 @@ const (
|
|||
)
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
var (
|
||||
// SessionWS holds all session channels. <sid, *util.WSChannel>
|
||||
|
@ -105,7 +105,7 @@ var mutex sync.Mutex
|
|||
// Invalid sessions: sessions that not used within 30 minutes, refers to WideSession.Updated field.
|
||||
func FixedTimeRelease() {
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
for _ = range time.Tick(time.Hour) {
|
||||
hour, _ := time.ParseDuration("-30m")
|
||||
|
@ -139,9 +139,9 @@ func (u *userReport) report() string {
|
|||
// FixedTimeReport reports the Wide sessions status periodically (10 minutes).
|
||||
func FixedTimeReport() {
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
for _ = range time.Tick(10*time.Minute) {
|
||||
for _ = range time.Tick(10 * time.Minute) {
|
||||
users := userReports{}
|
||||
processSum := 0
|
||||
|
||||
|
@ -284,8 +284,8 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// SaveContentHandler handles request of session content string.
|
||||
func SaveContentHandler(w http.ResponseWriter, r *http.Request) {
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
args := struct {
|
||||
Sid string
|
||||
|
@ -294,14 +294,14 @@ func SaveContentHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
wSession := WideSessions.Get(args.Sid)
|
||||
if nil == wSession {
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -477,7 +477,7 @@ func (sessions *wSessions) new(httpSession *sessions.Session, sid string) *WideS
|
|||
}
|
||||
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
for {
|
||||
ch := SessionWS[sid]
|
||||
|
@ -492,7 +492,7 @@ func (sessions *wSessions) new(httpSession *sessions.Session, sid string) *WideS
|
|||
|
||||
ch = SessionWS[sid]
|
||||
if nil == ch {
|
||||
return // release this gorutine
|
||||
return // release this goroutine
|
||||
}
|
||||
|
||||
logger.Trace(event)
|
||||
|
@ -500,7 +500,7 @@ func (sessions *wSessions) new(httpSession *sessions.Session, sid string) *WideS
|
|||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
fileType := "f"
|
||||
|
||||
if util.File.IsDir(path) {
|
||||
if gulu.File.IsDir(path) {
|
||||
fileType = "d"
|
||||
|
||||
if err = watcher.Add(path); nil != err {
|
||||
|
@ -526,7 +526,7 @@ func (sessions *wSessions) new(httpSession *sessions.Session, sid string) *WideS
|
|||
}()
|
||||
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
workspaces := filepath.SplitList(conf.GetUserWorkspace(uid))
|
||||
for _, workspace := range workspaces {
|
||||
|
|
|
@ -24,9 +24,9 @@ import (
|
|||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/util"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/wide/conf"
|
||||
"github.com/88250/wide/i18n"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -67,7 +67,7 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(user.Locale), "user": user,
|
||||
"ver": conf.WideVersion, "goos": runtime.GOOS, "goarch": runtime.GOARCH, "gover": runtime.Version(),
|
||||
"locales": i18n.GetLocalesNames(), "gofmts": util.Go.GetGoFormats(),
|
||||
"locales": i18n.GetLocalesNames(), "gofmts": gulu.Go.GetGoFormats(),
|
||||
"themes": conf.GetThemes(), "editorThemes": conf.GetEditorThemes()}
|
||||
|
||||
t, err := template.ParseFiles("views/preference.html")
|
||||
|
@ -93,8 +93,8 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// non-GET request as save request
|
||||
|
||||
result := util.NewResult()
|
||||
defer util.RetResult(w, r, result)
|
||||
result := gulu.Ret.NewResult()
|
||||
defer gulu.Ret.RetResult(w, r, result)
|
||||
|
||||
args := struct {
|
||||
FontFamily string
|
||||
|
@ -117,7 +117,7 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
logger.Error(err)
|
||||
result.Succ = false
|
||||
result.Code = -1
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -146,7 +146,11 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
user.Lived = now
|
||||
user.Updated = now
|
||||
|
||||
result.Succ = user.Save()
|
||||
if user.Save() {
|
||||
result.Code = 0
|
||||
} else {
|
||||
result.Code = -1
|
||||
}
|
||||
}
|
||||
|
||||
// FixedTimeSave saves online users' configurations periodically (1 minute).
|
||||
|
@ -154,7 +158,7 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// Main goal of this function is to save user session content, for restoring session content while user open Wide next time.
|
||||
func FixedTimeSave() {
|
||||
go func() {
|
||||
defer util.Recover()
|
||||
defer gulu.Panic.Recover(nil)
|
||||
|
||||
for _ = range time.Tick(time.Minute) {
|
||||
SaveOnlineUsers()
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -14,8 +14,16 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
body{
|
||||
overflow: auto;
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
min-height: 1px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.header {
|
||||
|
@ -61,7 +69,7 @@ body{
|
|||
}
|
||||
|
||||
.share-panel .font-ico:hover {
|
||||
transform:rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
|
|
@ -92,18 +92,16 @@ body {
|
|||
}
|
||||
|
||||
|
||||
.login__github {
|
||||
cursor: pointer;
|
||||
background-image: url("/static/images/github.png");
|
||||
height: 200px;
|
||||
.login__icon {
|
||||
width: 200px;
|
||||
background-size: cover;
|
||||
margin: 20px auto;
|
||||
background-position: center center;
|
||||
transition: all .15s ease-in-out;
|
||||
padding-right: 24px;
|
||||
color: #3b3e43;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.login__github:hover {
|
||||
background-image: url("/static/images/github.gif");
|
||||
.login__icon:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.btn {
|
||||
|
@ -127,6 +125,14 @@ body {
|
|||
box-shadow: 0 0 0 0.2em rgba(40, 167, 69, .3);
|
||||
}
|
||||
|
||||
.btn-blue {
|
||||
background-color: #4285f4;
|
||||
}
|
||||
|
||||
.btn-blue:hover {
|
||||
background-color: #2a75f3;
|
||||
}
|
||||
|
||||
.btn.btn-white,
|
||||
.btn.btn-red {
|
||||
color: #333;
|
||||
|
@ -216,4 +222,20 @@ body {
|
|||
font-size: 16px;
|
||||
}
|
||||
|
||||
.start {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.start .btn {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.start svg {
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.start__aciton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* end sign up */
|
|
@ -259,22 +259,19 @@
|
|||
|
||||
.bottom-window-group .output .start-build,
|
||||
.bottom-window-group .output .start-test, .start-vet,
|
||||
.bottom-window-group .output .start-install,
|
||||
.bottom-window-group .output .start-mod {
|
||||
.bottom-window-group .output .start-install {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.bottom-window-group .output .build-succ,
|
||||
.bottom-window-group .output .test-succ, .vet-succ,
|
||||
.bottom-window-group .output .install-succ,
|
||||
.bottom-window-group .output .mod-succ {
|
||||
.bottom-window-group .output .install-succ {
|
||||
color: rgb(0,153,0);
|
||||
}
|
||||
|
||||
.bottom-window-group .output .build-error,
|
||||
.bottom-window-group .output .test-error, .vet-error,
|
||||
.bottom-window-group .output .install-error,
|
||||
.bottom-window-group .output .mod-error {
|
||||
.bottom-window-group .output .install-error {
|
||||
color: #9d0000;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.dialog-close-icon,.dialog-close-icon:hover{text-decoration:none}.dialog-background{height:100%;left:0;opacity:.3;position:absolute;top:0;width:100%;filter:alpha(opacity=30);display:none;background-color:#000;z-index:99}.dialog-panel{position:absolute;z-index:100;display:none;-moz-user-select:none;user-select:none;box-shadow:0 2px 10px 1px #000}.dialog-title{float:left;line-height:22px;margin-left:3px;font-weight:700}.dialog-header-bg{height:23px;background-color:#bbb;cursor:move;width:100%}.dialog-close-icon{float:right;margin:3px}.dialog-main>div{width:100%}.dialog-footer{padding:10px;text-align:right}#dialogCloseEditor button,.dialog-footer button{margin:0 5px}#dialogAlert,#dialogRemoveConfirm,.dialog-form,.dialog-prompt{padding:10px 15px 0;overflow:hidden}.dialog-main input,.dialog-main select{width:100%;margin:2px auto}#dialogGoFilePrompt>ul{position:relative;height:260px;overflow:auto;margin-top:5px;background-color:#FFF;border:1px solid #919191}#dialogPreference{margin:10px}#dialogPreference .tabs-panel{padding:10px}#dialogPreference .preference{margin-bottom:10px}#dialogPreference img.gravatar{width:48px;height:48px}
|
||||
body,ul{margin:0}body,button,input{font-family:Helvetica}.list li,body{overflow:hidden}::-webkit-scrollbar{background:0 0;width:16px;height:16px}::-webkit-scrollbar-corner{display:none;background-color:transparent}::-webkit-scrollbar-thumb{border:0 solid transparent;border-right-width:4px;border-left-width:4px;border-radius:9px;box-shadow:inset 0 0 0 1px rgba(128,128,128,.2),inset 0 0 0 4px rgba(128,128,128,.2)}::-webkit-scrollbar-thumb:horizontal{border-bottom-width:4px;border-top-width:4px}body{font-size:13px;color:#000}ul{padding:0;list-style:none}*{box-sizing:border-box}a{color:#4183c4;text-decoration:none}a:hover{text-decoration:underline}img{vertical-align:middle}.fn-left{float:left}.fn-right{float:right}.fn-clear:after,.fn-clear:before{display:table;content:""}.fn-clear:after{clear:both}.fn-none{display:none}.ft-small{color:#999;font-size:12px}.ft-red{color:#9d0000}.list li{cursor:pointer;line-height:20px;padding:0 3px;word-wrap:normal;word-break:normal;white-space:nowrap;text-overflow:ellipsis}.list li.selected,.list li:hover{background-color:#3875d7;color:#FFF}.list li.selected .ft-small,.list li:hover .ft-small{color:#FFF}@font-face{font-family:icomoon;src:url(fonts/icomoon.eot?lqk80d);src:url(fonts/icomoon.eot?lqk80d#iefix) format('embedded-opentype'),url(fonts/icomoon.ttf?lqk80d) format('truetype'),url(fonts/icomoon.woff?lqk80d) format('woff'),url(fonts/icomoon.svg?lqk80d#icomoon) format('svg');font-weight:400;font-style:normal}[class*=" ico-"],[class^=ico-]{font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;cursor:pointer;font-size:13px;line-height:20px}.ico-qqz:before{content:"\e900"}.ico-find:before{content:"\e602"}.ico-findfiles:before{content:"\e603"}.ico-editor:before{content:"\e604"}.ico-notification:before{content:"\e607"}.ico-price:before{content:"\e616"}.ico-report:before{content:"\e605"}.ico-git:before{content:"\e624"}.ico-book:before{content:"\e623"}.ico-start:before{content:"\e9d7";text-shadow:0 0 rgba(0,0,0,.4)}.ico-tree:before{content:"\e600"}.ico-build:before{content:"\e601"}.ico-export:before{content:"\f0ed"}.ico-import:before{content:"\f0ee"}.ico-keyboard:before{content:"\f11c"}.ico-moveup:before{content:"\f148"}.ico-movedown:before{content:"\f149"}.ico-weibo:before{content:"\e621"}.ico-uniE608:before{content:"\e608"}.ico-max:before{content:"\e609"}.ico-remove:before{content:"\e60b"}.ico-buildrun:before{content:"\e60c"}.ico-about:before{content:"\e60d"}.ico-undo:before{content:"\e60e"}.ico-stop:before{content:"\e60f"}.ico-close:before{content:"\e611";text-shadow:0 0 rgba(0,0,0,.4)}.ico-format:before{content:"\e612"}.ico-restore:before{content:"\e613"}.toolbars .ico-restore:before{content:"\e60a"}.ico-min:before{content:"\e614";position:absolute;right:5px}.ico-redo:before{content:"\e615"}.ico-uniE617:before{content:"\e617"}.ico-signout:before{content:"\e618"}.ico-email:before{content:"\e619"}.ico-googleplus:before{content:"\e61a"}.ico-facebook:before{content:"\e61b"}.ico-twitter:before{content:"\e61c"}.ico-info:before{content:"\e61d"}.ico-goline:before{content:"\e61e"}.ico-share:before{content:"\e61f"}.ico-comment:before{content:"\e620"}.ico-github:before{content:"\f00a"}.ico-refresh:before{content:"\f021"}.ico-save:before{content:"\f0c7"}
|
||||
.frame li,.tabs>div{padding:0 5px;cursor:pointer}.footer .cursor,.frame li,.menu>ul>li>span,.notification-count,.tabs>div{cursor:pointer}.ico,.menu .split,.menu>ul>li,.tabs>div{float:left}.frame{position:absolute;width:320px;z-index:21;display:none}.frame li{line-height:25px}.frame li.disabled,.frame li.disabled .font-ico,.frame li.disabled:hover .font-ico{color:#999}.frame a{color:#000;text-decoration:none}.frame a:hover,.frame li:hover a{color:#FFF}.frame .space{display:inline-block;width:20px;height:15px}.frame .font-ico{margin-right:5px;width:15px;display:inline-block;text-align:center}.tabs{height:21px;overflow:hidden;width:100%}.tabs>div{line-height:20px;height:20px}.tabs>div>span.changed{font-weight:700}.tabs-panel{overflow:auto;flex:1;height:100%}.edit-exprinfo,.edit-panel{position:absolute;overflow:hidden}.menu{display:block!important}.menu>ul>li>span{font-size:12px;line-height:21px;padding:4px 7px}.menu .split{border-left:1px solid #919191;height:21px;margin:0 5px 0 0}.menu img.gravatar{float:left;margin:2px 8px;height:17px;width:17px;border-radius:9px}#buildRun{color:#6DB14C;font-size:19px}#buildRun.ico-stop{color:#9d0000;font-size:16px}.share-panel{position:absolute;z-index:20;width:190px;padding:5px 0;right:0;top:21px}.share-panel .font-ico{font-size:20px;transition:all .2s ease-out 0s;margin:0 5px;width:24px}.share-panel .font-ico:hover{transform:rotate(360deg)}.edit-panel{left:20%;width:60%;height:70%;flex-flow:column;display:flex}.toolbars{position:absolute;right:5px;top:1px}.ico{background-image:url(../images/ico-file.png);height:16px;margin:2px 0 0 -2px;width:16px}.edit-exprinfo{z-index:10;list-style:none;margin:0;padding:2px;-webkit-box-shadow:2px 3px 5px rgba(0,0,0,.2);-moz-box-shadow:2px 3px 5px rgba(0,0,0,.2);box-shadow:2px 3px 5px rgba(0,0,0,.2);border-radius:3px;border:1px solid silver;background:#fff;font-size:90%;max-height:20em;overflow-y:auto}.CodeMirror,.CodeMirror-hints{font-family:Consolas,'Courier New',monospace}.CodeMirror-hints .ico{margin:-1px 2px 0 -1px}.CodeMirror-focused .cm-matchhighlight{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);background-position:bottom;background-repeat:repeat-x}.CodeMirror-hint{padding-right:18px;max-width:none}.CodeMirror-hint:hover{background:#08f;color:#fff}.CodeMirror div.CodeMirror-cursor{border-left:2px solid #333}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:transparent}.bottom-window-group{background-color:#fff;flex-flow:column}.bottom-window-group .output{font-family:Consolas,Courier New,monospace;padding:0 5px;line-height:16px;font-size:12px;overflow-x:scroll;outline:0}.bottom-window-group .output pre{margin:0;font-family:Consolas,'Courier New',monospace}.bottom-window-group .output .start-build,.bottom-window-group .output .start-install,.bottom-window-group .output .start-mod,.bottom-window-group .output .start-test,.start-vet{color:#999}.bottom-window-group .output .build-succ,.bottom-window-group .output .install-succ,.bottom-window-group .output .mod-succ,.bottom-window-group .output .test-succ,.vet-succ{color:#090}.bottom-window-group .output .build-error,.bottom-window-group .output .install-error,.bottom-window-group .output .mod-error,.bottom-window-group .output .test-error,.vet-error{color:#9d0000}.bottom-window-group .output .stderr{color:gray;font-style:italic}.bottom-window-group .output .path{text-decoration:underline;cursor:pointer}.bottom-window-group table{width:100%}.bottom-window-group td{border-bottom:1px solid #919191;font-size:12px;line-height:19px}.bottom-window-group .notification{outline:0}.bottom-window-group .notification .severity,.bottom-window-group .notification .type{width:50px;padding:0 5px}.bottom-window-group .search{display:flex;flex-flow:column;outline:0}.footer{box-shadow:0 1px 0 0 rgba(255,255,255,.06) inset;padding-left:5px;line-height:18px;display:block!important}.notification-count{float:right;display:none;background-color:#9d0000;color:#FFF;margin:1px 5px;padding:0 2px;border-radius:3px;line-height:16px}
|
||||
.side{width:20%;position:absolute;height:100%;z-index:8;flex-flow:column;display:flex}.side-max{width:100%;z-index:11}.side-right .tabs-panel>div{overflow:auto}.side-right{flex-flow:column}#outline .ico{margin:1px 5px 0}.ico-func{background-position:-123px -21px}.ico-interface{background-position:-143px -21px}.ico-const{background-position:-103px -21px}.ico-var{background-position:-63px -21px}.ico-struct{background-position:-83px -21px}.ico-type{background-position:-163px -21px}.ico-package{background-position:-183px -21px}.ztree{width:100%;padding:0;outline:0;border:0}.ztree li a.curSelectedNode{background-color:#3875d7;border-width:0;color:#fff;height:18px;opacity:1}.ztree li a:hover{text-decoration:none}.ztree li>a>span.button,.ztree li>a>span.button.ico-ztree-dir,.ztree li>a>span.button.ico-ztree-dir-api,.ztree li>a>span.button.ico-ztree-dir-workspace{margin-right:2px}.ztree li>a>span.button{background-image:url(../images/ico-file.png);margin-right:0}.ico-ztree-dir{background-position:-2px -23px}.ico-ztree-dir-api{background-position:-22px -23px}.ico-ztree-dir-workspace{background-position:-42px -23px}.ico-ztree-html{background-position:-4px -2px}.ico-ztree-go{background-position:-22px -2px}.ico-ztree-css{background-position:-42px -2px}.ico-ztree-img{background-position:-63px -2px}.ico-ztree-other{background-position:-83px -2px}.ico-ztree-text{background-position:-103px -2px}.ico-ztree-sql{background-position:-123px -2px}.ico-ztree-pro{background-position:-142px -2px}.ico-ztree-md{background-position:-162px -2px}.ico-ztree-js{background-position:-182px -2px}.ico-ztree-xml{background-position:-202px -2px}
|
||||
#startPage{padding:50px 70px;line-height:28px;white-space:normal;word-wrap:break-word;overflow:auto}#startPage a{color:#4183c4;text-decoration:none}#startPage a:hover{text-decoration:underline}#startPage .title{background-color:#BBB;border-bottom-width:0!important;border-radius:3px 3px 0 0;font-size:15px;margin-bottom:10px;padding:5px 10px;color:#FFF}#startPage .details li.border,#startPage .news li{border-bottom:1px solid #919191}#startPage .details{width:30%;float:left}#startPage .details label{color:#666}#startPage .details li.border{padding-bottom:5px;margin-bottom:5px}#startPage .details li.border.workspace{line-height:18px;padding-bottom:10px!important;word-wrap:break-word;white-space:normal;word-break:break-all}#startPage .news{width:60%;float:right;border-left:1px solid #f1f1f1;margin-left:10%;padding-left:10%;white-space:nowrap;overflow:hidden}#startPage .date{color:#bbb;font-size:13px;word-wrap:normal;white-space:nowrap}
|
||||
#dialogAboutDialog .dialog-main{background-color:#FFF}#dialogAbout{margin:35px 20px;line-height:28px}#dialogAbout .item{margin:0 10px}#dialogAbout a{color:#4183c4;text-decoration:none}#dialogAbout a:hover{text-decoration:underline}#dialogAbout label{color:#666}#dialogAbout img{width:100px;float:left;margin-right:60px}#dialogAbout .space{margin-bottom:6px;border-bottom:1px solid #919191;padding-bottom:6px}#dialogAbout .thx ul{margin-left:50px}#dialogAbout .thx a{width:80px;display:inline-block}#dialogAbout .license{color:#999;font-size:12px;line-height:normal;height:85px;overflow-x:hidden;word-wrap:break-word}
|
||||
.dialog-background{height:100%;left:0;opacity:.3;position:absolute;top:0;width:100%;display:none;background-color:#000;z-index:99}.dialog-panel{position:absolute;z-index:100;display:none;-moz-user-select:none;user-select:none;box-shadow:0 2px 10px 1px #000}.dialog-title{float:left;line-height:22px;margin-left:3px;font-weight:700}.dialog-header-bg{height:23px;background-color:#bbb;cursor:move;width:100%}.dialog-close-icon{float:right;margin:3px;text-decoration:none}.dialog-close-icon:hover{text-decoration:none}.dialog-main>div{width:100%}.dialog-footer{padding:10px;text-align:right}#dialogCloseEditor button,.dialog-footer button{margin:0 5px}#dialogAlert,#dialogRemoveConfirm,.dialog-form,.dialog-prompt{padding:10px 15px 0;overflow:hidden}.dialog-main input,.dialog-main select{width:100%;margin:2px auto}#dialogGoFilePrompt>ul{position:relative;height:260px;overflow:auto;margin-top:5px;background-color:#fff;border:1px solid #919191}#dialogPreference{margin:10px}#dialogPreference .tabs-panel{padding:10px}#dialogPreference .preference{margin-bottom:10px}#dialogPreference img.gravatar{width:48px;height:48px}
|
||||
::-webkit-scrollbar{background:0 0;width:16px;height:16px}::-webkit-scrollbar-corner{display:none;background-color:transparent}::-webkit-scrollbar-thumb{border:solid 0 transparent;border-right-width:4px;border-left-width:4px;border-radius:9px;box-shadow:inset 0 0 0 1px rgba(128,128,128,.2),inset 0 0 0 4px rgba(128,128,128,.2)}::-webkit-scrollbar-thumb:horizontal{border-bottom-width:4px;border-top-width:4px}body{font-size:13px;margin:0;color:#000;overflow:hidden;font-family:Helvetica}ul{padding:0;margin:0;list-style:none}*{box-sizing:border-box}a{color:#4183c4;text-decoration:none}a:hover{text-decoration:underline}img{vertical-align:middle}button,input{font-family:Helvetica}.fn-left{float:left}.fn-right{float:right}.fn-clear:after,.fn-clear:before{display:table;content:""}.fn-clear:after{clear:both}.fn-none{display:none}.ft-small{color:#999;font-size:12px}.ft-red{color:#9d0000}.list li{cursor:pointer;line-height:20px;padding:0 3px;word-wrap:normal;word-break:normal;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list li.selected,.list li:hover{background-color:#3875d7;color:#fff}.list li.selected .ft-small,.list li:hover .ft-small{color:#fff}@font-face{font-family:icomoon;src:url(fonts/icomoon.eot?lqk80d);src:url(fonts/icomoon.eot?lqk80d#iefix) format('embedded-opentype'),url(fonts/icomoon.ttf?lqk80d) format('truetype'),url(fonts/icomoon.woff?lqk80d) format('woff'),url(fonts/icomoon.svg?lqk80d#icomoon) format('svg');font-weight:400;font-style:normal}[class*=" ico-"],[class^=ico-]{font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;cursor:pointer;font-size:13px;line-height:20px}.ico-qqz:before{content:"\e900"}.ico-find:before{content:"\e602"}.ico-findfiles:before{content:"\e603"}.ico-editor:before{content:"\e604"}.ico-notification:before{content:"\e607"}.ico-price:before{content:"\e616"}.ico-report:before{content:"\e605"}.ico-git:before{content:"\e624"}.ico-book:before{content:"\e623"}.ico-start:before{content:"\e9d7";text-shadow:0 0 rgba(0,0,0,.4)}.ico-tree:before{content:"\e600"}.ico-build:before{content:"\e601"}.ico-export:before{content:"\f0ed"}.ico-import:before{content:"\f0ee"}.ico-keyboard:before{content:"\f11c"}.ico-moveup:before{content:"\f148"}.ico-movedown:before{content:"\f149"}.ico-weibo:before{content:"\e621"}.ico-uniE608:before{content:"\e608"}.ico-max:before{content:"\e609"}.ico-remove:before{content:"\e60b"}.ico-buildrun:before{content:"\e60c"}.ico-about:before{content:"\e60d"}.ico-undo:before{content:"\e60e"}.ico-stop:before{content:"\e60f"}.ico-close:before{content:"\e611";text-shadow:0 0 rgba(0,0,0,.4)}.ico-format:before{content:"\e612"}.ico-restore:before{content:"\e613"}.toolbars .ico-restore:before{content:"\e60a"}.ico-min:before{content:"\e614";position:absolute;right:5px}.ico-redo:before{content:"\e615"}.ico-uniE617:before{content:"\e617"}.ico-signout:before{content:"\e618"}.ico-email:before{content:"\e619"}.ico-googleplus:before{content:"\e61a"}.ico-facebook:before{content:"\e61b"}.ico-twitter:before{content:"\e61c"}.ico-info:before{content:"\e61d"}.ico-goline:before{content:"\e61e"}.ico-share:before{content:"\e61f"}.ico-comment:before{content:"\e620"}.ico-github:before{content:"\f00a"}.ico-refresh:before{content:"\f021"}.ico-save:before{content:"\f0c7"}
|
||||
.frame{position:absolute;width:320px;z-index:21;display:none}.frame li{padding:0 5px;line-height:25px;cursor:pointer}.frame li.disabled,.frame li.disabled .font-ico,.frame li.disabled:hover .font-ico{color:#999}.frame a{color:#000;text-decoration:none}.frame a:hover,.frame li:hover a{color:#fff}.frame .space{display:inline-block;width:20px;height:15px}.frame .font-ico{margin-right:5px;width:15px;display:inline-block;text-align:center}.tabs{height:21px;overflow:hidden;width:100%}.tabs>div{float:left;line-height:20px;height:20px;padding:0 5px;cursor:pointer}.tabs>div>span.changed{font-weight:700}.tabs-panel{overflow:auto;flex:1;height:100%}.menu{display:block!important}.menu>ul>li{float:left}.menu>ul>li>span{font-size:12px;line-height:21px;cursor:pointer;padding:4px 7px}.menu .split{float:left;border-left:1px solid #919191;height:21px;margin:0 5px 0 0}.menu img.gravatar{float:left;margin:2px 8px;height:17px;width:17px;border-radius:9px}#buildRun{color:#6db14c;font-size:19px}#buildRun.ico-stop{color:#9d0000;font-size:16px}.share-panel{position:absolute;z-index:20;width:190px;padding:5px 0;right:0;top:21px}.share-panel .font-ico{font-size:20px;transition:all .2s ease-out 0s;margin:0 5px;width:24px}.share-panel .font-ico:hover{transform:rotate(360deg)}.edit-panel{position:absolute;left:20%;width:60%;height:70%;overflow:hidden;flex-flow:column;display:flex}.toolbars{position:absolute;right:5px;top:1px}.ico{background-image:url(../images/ico-file.png);float:left;height:16px;margin:2px 0 0 -2px;width:16px}.edit-exprinfo{position:absolute;z-index:10;overflow:hidden;list-style:none;margin:0;padding:2px;-webkit-box-shadow:2px 3px 5px rgba(0,0,0,.2);-moz-box-shadow:2px 3px 5px rgba(0,0,0,.2);box-shadow:2px 3px 5px rgba(0,0,0,.2);border-radius:3px;border:1px solid silver;background:#fff;font-size:90%;max-height:20em;overflow-y:auto}.CodeMirror,.CodeMirror-hints{font-family:Consolas,'Courier New',monospace}.CodeMirror-hints .ico{margin:-1px 2px 0 -1px}.CodeMirror-focused .cm-matchhighlight{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);background-position:bottom;background-repeat:repeat-x}.CodeMirror-hint{padding-right:18px;max-width:none}.CodeMirror-hint:hover{background:#08f;color:#fff}.CodeMirror div.CodeMirror-cursor{border-left:2px solid #333}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:transparent}.bottom-window-group{background-color:#fff;flex-flow:column}.bottom-window-group .output{font-family:Consolas,Courier New,monospace;padding:0 5px;line-height:16px;font-size:12px;overflow-x:scroll;outline:0}.bottom-window-group .output pre{margin:0;font-family:Consolas,'Courier New',monospace}.bottom-window-group .output .start-build,.bottom-window-group .output .start-install,.bottom-window-group .output .start-test,.start-vet{color:#999}.bottom-window-group .output .build-succ,.bottom-window-group .output .install-succ,.bottom-window-group .output .test-succ,.vet-succ{color:#090}.bottom-window-group .output .build-error,.bottom-window-group .output .install-error,.bottom-window-group .output .test-error,.vet-error{color:#9d0000}.bottom-window-group .output .stderr{color:gray;font-style:italic}.bottom-window-group .output .path{text-decoration:underline;cursor:pointer}.bottom-window-group table{width:100%}.bottom-window-group td{border-bottom:1px solid #919191;font-size:12px;line-height:19px}.bottom-window-group .notification{outline:0}.bottom-window-group .notification .severity,.bottom-window-group .notification .type{width:50px;padding:0 5px}.bottom-window-group .search{display:flex;flex-flow:column;outline:0}.footer{box-shadow:0 1px 0 0 rgba(255,255,255,.06) inset;padding-left:5px;line-height:18px;display:block!important}.footer .cursor{cursor:pointer}.notification-count{float:right;display:none;cursor:pointer;background-color:#9d0000;color:#fff;margin:1px 5px;padding:0 2px;border-radius:3px;line-height:16px}
|
||||
.side{width:20%;position:absolute;height:100%;z-index:8;flex-flow:column;display:flex}.side-max{width:100%;z-index:11}.side-right .tabs-panel>div{overflow:auto}.side-right{flex-flow:column}#outline .ico{margin:1px 5px 0 5px}.ico-func{background-position:-123px -21px}.ico-interface{background-position:-143px -21px}.ico-const{background-position:-103px -21px}.ico-var{background-position:-63px -21px}.ico-struct{background-position:-83px -21px}.ico-type{background-position:-163px -21px}.ico-package{background-position:-183px -21px}.ztree{width:100%;padding:0;outline:0;border:0}.ztree li a.curSelectedNode{background-color:#3875d7;border-width:0;color:#fff;height:18px;opacity:1}.ztree li a:hover{text-decoration:none}.ztree li>a>span.button,.ztree li>a>span.button.ico-ztree-dir,.ztree li>a>span.button.ico-ztree-dir-api,.ztree li>a>span.button.ico-ztree-dir-workspace{margin-right:2px}.ztree li>a>span.button{background-image:url(../images/ico-file.png);margin-right:0}.ico-ztree-dir{background-position:-2px -23px}.ico-ztree-dir-api{background-position:-22px -23px}.ico-ztree-dir-workspace{background-position:-42px -23px}.ico-ztree-html{background-position:-4px -2px}.ico-ztree-go{background-position:-22px -2px}.ico-ztree-css{background-position:-42px -2px}.ico-ztree-img{background-position:-63px -2px}.ico-ztree-other{background-position:-83px -2px}.ico-ztree-text{background-position:-103px -2px}.ico-ztree-sql{background-position:-123px -2px}.ico-ztree-pro{background-position:-142px -2px}.ico-ztree-md{background-position:-162px -2px}.ico-ztree-js{background-position:-182px -2px}.ico-ztree-xml{background-position:-202px -2px}
|
||||
#startPage{padding:50px 70px;line-height:28px;white-space:normal;word-wrap:break-word;overflow:auto}#startPage a{color:#4183c4;text-decoration:none}#startPage a:hover{text-decoration:underline}#startPage .title{background-color:#bbb;border-bottom-width:0!important;border-radius:3px 3px 0 0;font-size:15px;margin-bottom:10px;padding:5px 10px;color:#fff}#startPage .details{width:30%;float:left}#startPage .details label{color:#666}#startPage .details li.border{padding-bottom:5px;margin-bottom:5px;border-bottom:1px solid #919191}#startPage .details li.border.workspace{line-height:18px;padding-bottom:10px!important;word-wrap:break-word;white-space:normal;word-break:break-all}#startPage .news{width:60%;float:right;border-left:1px solid #f1f1f1;margin-left:10%;padding-left:10%;white-space:nowrap;overflow:hidden}#startPage .news li{border-bottom:1px solid #919191}#startPage .date{color:#bbb;font-size:13px;word-wrap:normal;white-space:nowrap}
|
||||
#dialogAboutDialog .dialog-main{background-color:#fff}#dialogAbout{margin:35px 20px;line-height:28px}#dialogAbout .item{margin:0 10px}#dialogAbout a{color:#4183c4;text-decoration:none}#dialogAbout a:hover{text-decoration:underline}#dialogAbout label{color:#666}#dialogAbout img{width:100px;float:left;margin-right:60px}#dialogAbout .space{margin-bottom:6px;border-bottom:1px solid #919191;padding-bottom:6px}#dialogAbout .thx ul{margin-left:50px}#dialogAbout .thx a{width:80px;display:inline-block}#dialogAbout .license{color:#999;font-size:12px;line-height:normal;height:85px;overflow-x:hidden;word-wrap:break-word}
|
Binary file not shown.
Before Width: | Height: | Size: 69 KiB |
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
|
@ -248,7 +248,7 @@ var editors = {
|
|||
after: function () {
|
||||
$("#startPage").load('/start?sid=' + config.wideSessionId);
|
||||
$.ajax({
|
||||
url: "https://hacpai.com/apis/articles?tags=wide,golang&p=1&size=20",
|
||||
url: "https://ld246.com/apis/articles?tags=wide,golang&p=1&size=20",
|
||||
type: "GET",
|
||||
dataType: "jsonp",
|
||||
jsonp: "callback",
|
||||
|
@ -265,7 +265,7 @@ var editors = {
|
|||
}
|
||||
|
||||
var listHTML = "<ul><li class='title'>" + config.label.community +
|
||||
"<a href='https://hacpai.com/article/1437497122181' target='_blank' class='fn-right'>边看边练</li>";
|
||||
"<a href='https://ld246.com/article/1437497122181' target='_blank' class='fn-right'>边看边练</li>";
|
||||
for (var i = 0; i < length; i++) {
|
||||
var article = articles[i];
|
||||
listHTML += "<li>"
|
||||
|
@ -439,7 +439,7 @@ var editors = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -587,7 +587,7 @@ var editors = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -617,7 +617,7 @@ var editors = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -163,7 +163,7 @@ var menu = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (result.succ) {
|
||||
if (0 == result.code) {
|
||||
window.location.href = "/login";
|
||||
}
|
||||
}
|
||||
|
@ -172,33 +172,6 @@ var menu = {
|
|||
openAbout: function () {
|
||||
$("#dialogAbout").dialog("open");
|
||||
},
|
||||
gomod: function () {
|
||||
menu.saveAllFiles();
|
||||
|
||||
var currentPath = editors.getCurrentPath();
|
||||
if (!currentPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($(".menu li.go-mod").hasClass("disabled")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var request = newWideRequest();
|
||||
request.file = currentPath;
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/go/mod',
|
||||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
beforeSend: function () {
|
||||
bottomGroup.resetOutput();
|
||||
},
|
||||
success: function (result) {
|
||||
}
|
||||
});
|
||||
},
|
||||
goinstall: function () {
|
||||
menu.saveAllFiles();
|
||||
|
||||
|
@ -467,7 +440,7 @@ var menu = {
|
|||
url: '/preference',
|
||||
data: JSON.stringify(request),
|
||||
success: function (result, textStatus, jqXHR) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
* @author <a href="http://vanessa.b3log.org">Liyuan Li</a>
|
||||
* @author <a href="http://88250.b3log.org">Liang Ding</a>
|
||||
* @version 1.0.0.1, Dec 8, 2015
|
||||
* @version 1.0.0.2, Jun 23, 2019
|
||||
*/
|
||||
var notification = {
|
||||
init: function () {
|
||||
|
@ -35,7 +35,7 @@ var notification = {
|
|||
var notificationWS = new ReconnectingWebSocket(config.channel + '/notification/ws?sid=' + config.wideSessionId);
|
||||
|
||||
notificationWS.onopen = function () {
|
||||
console.log('[notification onopen] connected');
|
||||
// console.log('[notification onopen] connected');
|
||||
};
|
||||
|
||||
notificationWS.onmessage = function (e) {
|
||||
|
@ -44,7 +44,7 @@ var notification = {
|
|||
notificationHTML = '';
|
||||
|
||||
if (data.cmd && "init-notification" === data.cmd) {
|
||||
console.log('[notification onmessage]' + e.data);
|
||||
// console.log('[notification onmessage]' + e.data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -58,11 +58,11 @@ var notification = {
|
|||
};
|
||||
|
||||
notificationWS.onclose = function (e) {
|
||||
console.log('[notification onclose] disconnected (' + e.code + ')');
|
||||
// console.log('[notification onclose] disconnected (' + e.code + ')');
|
||||
};
|
||||
|
||||
notificationWS.onerror = function (e) {
|
||||
console.log('[notification onerror]');
|
||||
console.log('[notification onerror]', e);
|
||||
};
|
||||
}
|
||||
};
|
|
@ -19,14 +19,13 @@
|
|||
*
|
||||
* @author <a href="http://vanessa.b3log.org">Liyuan Li</a>
|
||||
* @author <a href="http://88250.b3log.org">Liang Ding</a>
|
||||
* @version 1.0.0.2, Oct 5, 2018
|
||||
* @version 1.0.0.3, Jun 23, 2019
|
||||
*/
|
||||
var playground = {
|
||||
autocompleteMutex: false,
|
||||
editor: undefined,
|
||||
pid: undefined,
|
||||
_resize: function () {
|
||||
$('#goNews, #editorDivWrap').height($(window).height() - 40 - $(".footer").height());
|
||||
playground.editor.setSize("auto", ($("#editorDiv").parent().height() * 0.7) + "px");
|
||||
},
|
||||
_initShare: function () {
|
||||
|
@ -82,7 +81,6 @@ var playground = {
|
|||
var autocompleteHints = [];
|
||||
|
||||
if (playground.autocompleteMutex && editor.state.completionActive) {
|
||||
console.log(1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -275,23 +273,23 @@ var playground = {
|
|||
var sessionWS = new ReconnectingWebSocket(config.channel + '/session/ws?sid=' + config.wideSessionId);
|
||||
|
||||
sessionWS.onopen = function () {
|
||||
console.log('[session onopen] connected');
|
||||
// console.log('[session onopen] connected');
|
||||
};
|
||||
|
||||
sessionWS.onmessage = function (e) {
|
||||
console.log('[session onmessage]' + e.data);
|
||||
// console.log('[session onmessage]' + e.data);
|
||||
};
|
||||
sessionWS.onclose = function (e) {
|
||||
console.log('[session onclose] disconnected (' + e.code + ')');
|
||||
// console.log('[session onclose] disconnected (' + e.code + ')');
|
||||
};
|
||||
sessionWS.onerror = function (e) {
|
||||
console.log('[session onerror] ' + JSON.parse(e));
|
||||
// console.log('[session onerror] ' + JSON.parse(e));
|
||||
};
|
||||
|
||||
var playgroundWS = new ReconnectingWebSocket(config.channel + '/playground/ws?sid=' + config.wideSessionId);
|
||||
|
||||
playgroundWS.onopen = function () {
|
||||
console.log('[playground onopen] connected');
|
||||
// console.log('[playground onopen] connected');
|
||||
};
|
||||
|
||||
playgroundWS.onmessage = function (e) {
|
||||
|
@ -303,22 +301,30 @@ var playground = {
|
|||
|
||||
playground.pid = data.pid;
|
||||
|
||||
var output = data.output;
|
||||
var output = $("#output").html();
|
||||
if ("" === output) {
|
||||
output = "<pre>" + data.output + "</pre>";
|
||||
} else {
|
||||
output = output.replace(/<\/pre>$/g, data.output + '</pre>');
|
||||
}
|
||||
output = output.replace(/\r/g, '');
|
||||
output = output.replace(/\n/g, '<br/>');
|
||||
var oldOutput = $("#output").html();
|
||||
$("#output").html(oldOutput + output);
|
||||
if (-1 !== output.indexOf("<br/>")) {
|
||||
output = Autolinker.link(output);
|
||||
}
|
||||
|
||||
$("#output").html(output);
|
||||
};
|
||||
playgroundWS.onclose = function (e) {
|
||||
console.log('[playground onclose] disconnected (' + e.code + ')');
|
||||
// console.log('[playground onclose] disconnected (' + e.code + ')');
|
||||
};
|
||||
playgroundWS.onerror = function (e) {
|
||||
console.log('[playground onerror] ' + JSON.parse(e));
|
||||
console.log('[playground onerror] ', e);
|
||||
};
|
||||
},
|
||||
_initGoNews: function () {
|
||||
$.ajax({
|
||||
url: "https://hacpai.com/apis/articles?tags=wide,golang&p=1&size=20",
|
||||
url: "https://ld246.com/apis/articles?tags=wide,golang&p=1&size=20",
|
||||
type: "GET",
|
||||
dataType: "jsonp",
|
||||
jsonp: "callback",
|
||||
|
@ -331,7 +337,7 @@ var playground = {
|
|||
var length = articles.length;
|
||||
|
||||
var listHTML = "<ul><li class='title'>" + config.label.community +
|
||||
"<a href='https://hacpai.com/article/1437497122181' target='_blank' class='fn-right'>边看边练</li>";
|
||||
"<a href='https://ld246.com/article/1437497122181' target='_blank' class='fn-right'>边看边练</li>";
|
||||
for (var i = 0; i < length; i++) {
|
||||
var article = articles[i];
|
||||
listHTML += "<li>"
|
||||
|
@ -365,8 +371,7 @@ var playground = {
|
|||
|
||||
playground.editor.setValue(data.code);
|
||||
|
||||
if (!result.succ) {
|
||||
console.log(data);
|
||||
if (0 != result.code) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -438,7 +443,7 @@ var playground = {
|
|||
playground.editor.setValue(data.code);
|
||||
playground.editor.setCursor(cursor);
|
||||
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -452,13 +457,11 @@ var playground = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
console.log(result);
|
||||
|
||||
var data = result.data;
|
||||
|
||||
$("#output").html(data.output);
|
||||
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* @file session.js
|
||||
*
|
||||
* @author <a href="http://vanessa.b3log.org">Liyuan Li</a>
|
||||
* @version 1.1.0.1, Dec 8, 2015
|
||||
* @version 1.1.0.2, Jun 23, 2019
|
||||
*/
|
||||
var session = {
|
||||
init: function () {
|
||||
|
@ -158,8 +158,6 @@ var session = {
|
|||
var sessionWS = new ReconnectingWebSocket(config.channel + '/session/ws?sid=' + config.wideSessionId);
|
||||
|
||||
sessionWS.onopen = function () {
|
||||
console.log('[session onopen] connected');
|
||||
|
||||
var dateFormat = function (time, fmt) {
|
||||
var date = new Date(time);
|
||||
var dateObj = {
|
||||
|
@ -238,7 +236,7 @@ var session = {
|
|||
}
|
||||
};
|
||||
sessionWS.onclose = function (e) {
|
||||
console.log('[session onclose] disconnected (' + e.code + ')');
|
||||
// console.log('[session onclose] disconnected (' + e.code + ')');
|
||||
|
||||
var data = {type: "Network", severity: "ERROR",
|
||||
message: "Disconnected from server, trying to reconnect it [sid=" + config.wideSessionId + "]"},
|
||||
|
@ -253,7 +251,7 @@ var session = {
|
|||
$(".notification-count").show();
|
||||
};
|
||||
sessionWS.onerror = function (e) {
|
||||
console.log('[session onerror]');
|
||||
console.log('[session onerror]', e);
|
||||
};
|
||||
}
|
||||
};
|
|
@ -164,7 +164,7 @@ var tree = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
$("#dialogAlert").dialog("open", result.msg);
|
||||
|
||||
return false;
|
||||
|
@ -190,7 +190,7 @@ var tree = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
$("#dialogAlert").dialog("open", result.msg);
|
||||
|
||||
return false;
|
||||
|
@ -220,7 +220,7 @@ var tree = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (result.succ) {
|
||||
if (0 == result.code) {
|
||||
var $dirRMenu = $("#dirRMenu");
|
||||
var $fileRMenu = $("#fileRMenu");
|
||||
var setting = {
|
||||
|
@ -374,7 +374,7 @@ var tree = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
$("#dialogAlert").dialog("open", result.msg);
|
||||
|
||||
return false;
|
||||
|
@ -463,7 +463,7 @@ var tree = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -499,7 +499,7 @@ var tree = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
$("#dialogRenamePrompt").dialog("close");
|
||||
bottomGroup.tabs.setCurrent("notification");
|
||||
windows.flowBottom();
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
* @author <a href="http://vanessa.b3log.org">Liyuan Li</a>
|
||||
* @author <a href="http://88250.b3log.org">Liang Ding</a>
|
||||
* @version 1.0.0.1, Dec 8, 2015
|
||||
* @version 1.0.0.2, Jun 23, 2019
|
||||
*/
|
||||
var wide = {
|
||||
curNode: undefined,
|
||||
|
@ -42,7 +42,7 @@ var wide = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ var wide = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
$("#dialogRemoveConfirm").dialog("close");
|
||||
bottomGroup.tabs.setCurrent("notification");
|
||||
windows.flowBottom();
|
||||
|
@ -163,7 +163,7 @@ var wide = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
$("#dialogNewFilePrompt").dialog("close");
|
||||
bottomGroup.tabs.setCurrent("notification");
|
||||
windows.flowBottom();
|
||||
|
@ -207,7 +207,7 @@ var wide = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
$("#dialogNewDirPrompt").dialog("close");
|
||||
bottomGroup.tabs.setCurrent("notification");
|
||||
windows.flowBottom();
|
||||
|
@ -268,7 +268,7 @@ var wide = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -343,11 +343,11 @@ var wide = {
|
|||
_initWS: function () {
|
||||
var outputWS = new ReconnectingWebSocket(config.channel + '/output/ws?sid=' + config.wideSessionId);
|
||||
outputWS.onopen = function () {
|
||||
console.log('[output onopen] connected');
|
||||
// console.log('[output onopen] connected');
|
||||
};
|
||||
|
||||
outputWS.onmessage = function (e) {
|
||||
console.log('[output onmessage]' + e.data);
|
||||
// console.log('[output onmessage]' + e.data);
|
||||
var data = JSON.parse(e.data);
|
||||
|
||||
if (goLintFound) {
|
||||
|
@ -390,14 +390,12 @@ var wide = {
|
|||
case 'start-test':
|
||||
case 'start-vet':
|
||||
case 'start-install':
|
||||
case 'start-mod':
|
||||
bottomGroup.fillOutput(data.output);
|
||||
|
||||
break;
|
||||
case 'go test':
|
||||
case 'go vet':
|
||||
case 'go install':
|
||||
case 'go mod':
|
||||
bottomGroup.fillOutput($('.bottom-window-group .output > div').html() + data.output);
|
||||
|
||||
break;
|
||||
|
@ -445,7 +443,7 @@ var wide = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (!result.succ) {
|
||||
if (0 != result.code) {
|
||||
$("#dialogAlert").dialog("open", result.msg);
|
||||
|
||||
return false;
|
||||
|
@ -465,10 +463,10 @@ var wide = {
|
|||
}
|
||||
};
|
||||
outputWS.onclose = function (e) {
|
||||
console.log('[output onclose] disconnected (' + e.code + ')');
|
||||
// console.log('[output onclose] disconnected (' + e.code + ')');
|
||||
};
|
||||
outputWS.onerror = function (e) {
|
||||
console.log('[output onerror]');
|
||||
console.log('[output onerror]',e);
|
||||
};
|
||||
},
|
||||
_initFooter: function () {
|
||||
|
@ -616,7 +614,7 @@ var wide = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (result.succ) {
|
||||
if (0 == result.code) {
|
||||
editor.setValue(result.data.code);
|
||||
editor.setCursor(cursor);
|
||||
editor.scrollTo(null, scrollInfo.top);
|
||||
|
@ -649,7 +647,7 @@ var wide = {
|
|||
data: JSON.stringify(request),
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (result.succ) {
|
||||
if (0 == result.code) {
|
||||
formatted = result.data.code;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
This directory is used to unit-test.
|
159
util/file.go
159
util/file.go
|
@ -1,159 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/b3log/wide/log"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
var fileLogger = log.NewLogger(os.Stdout)
|
||||
|
||||
type myfile struct{}
|
||||
|
||||
// File utilities.
|
||||
var File = myfile{}
|
||||
|
||||
// GetFileSize get the length in bytes of file of the specified path.
|
||||
func (*myfile) GetFileSize(path string) int64 {
|
||||
fi, err := os.Stat(path)
|
||||
if nil != err {
|
||||
fileLogger.Error(err)
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
return fi.Size()
|
||||
}
|
||||
|
||||
// IsExist determines whether the file spcified by the given path is exists.
|
||||
func (*myfile) IsExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
|
||||
return err == nil || os.IsExist(err)
|
||||
}
|
||||
|
||||
// IsBinary determines whether the specified content is a binary file content.
|
||||
func (*myfile) IsBinary(content string) bool {
|
||||
for _, b := range content {
|
||||
if 0 == b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsImg determines whether the specified extension is a image.
|
||||
func (*myfile) IsImg(extension string) bool {
|
||||
ext := strings.ToLower(extension)
|
||||
|
||||
switch ext {
|
||||
case ".jpg", ".jpeg", ".bmp", ".gif", ".png", ".svg", ".ico":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsDir determines whether the specified path is a directory.
|
||||
func (*myfile) IsDir(path string) bool {
|
||||
fio, err := os.Lstat(path)
|
||||
if nil != err {
|
||||
fileLogger.Warnf("Determines whether [%s] is a directory failed: [%v]", path, err)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return fio.IsDir()
|
||||
}
|
||||
|
||||
// CopyFile copies the source file to the dest file.
|
||||
func (*myfile) CopyFile(source string, dest string) (err error) {
|
||||
sourcefile, err := os.Open(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer sourcefile.Close()
|
||||
|
||||
destfile, err := os.Create(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer destfile.Close()
|
||||
|
||||
_, err = io.Copy(destfile, sourcefile)
|
||||
if err == nil {
|
||||
sourceinfo, err := os.Stat(source)
|
||||
if err != nil {
|
||||
err = os.Chmod(dest, sourceinfo.Mode())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyDir copies the source directory to the dest directory.
|
||||
func (*myfile) CopyDir(source string, dest string) (err error) {
|
||||
sourceinfo, err := os.Stat(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create dest dir
|
||||
err = os.MkdirAll(dest, sourceinfo.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
directory, err := os.Open(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer directory.Close()
|
||||
|
||||
objects, err := directory.Readdir(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, obj := range objects {
|
||||
srcFilePath := filepath.Join(source, obj.Name())
|
||||
destFilePath := filepath.Join(dest, obj.Name())
|
||||
|
||||
if obj.IsDir() {
|
||||
// create sub-directories - recursively
|
||||
err = File.CopyDir(srcFilePath, destFilePath)
|
||||
if err != nil {
|
||||
fileLogger.Error(err)
|
||||
}
|
||||
} else {
|
||||
err = File.CopyFile(srcFilePath, destFilePath)
|
||||
if err != nil {
|
||||
fileLogger.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetFileSize(t *testing.T) {
|
||||
size := File.GetFileSize(".")
|
||||
|
||||
t.Log("size of file [.] is [" + strconv.FormatInt(size, 10) + "]")
|
||||
}
|
||||
|
||||
func TestIsExist(t *testing.T) {
|
||||
if !File.IsExist(".") {
|
||||
t.Error(". must exist")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestIdBinary(t *testing.T) {
|
||||
if File.IsBinary("not binary content") {
|
||||
t.Error("The content should not be binary")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsImg(t *testing.T) {
|
||||
if !File.IsImg(".jpg") {
|
||||
t.Error(".jpg should be a valid extension of a image file")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsDir(t *testing.T) {
|
||||
if !File.IsDir(".") {
|
||||
t.Error(". should be a directory")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyDir(t *testing.T) {
|
||||
dest := filepath.Join(testDir, "util")
|
||||
|
||||
err := File.CopyDir(".", dest)
|
||||
if nil != err {
|
||||
t.Error("Copy dir error: ", err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyFile(t *testing.T) {
|
||||
dest := filepath.Join(testDir, "file.go")
|
||||
|
||||
err := File.CopyFile("./file.go", dest)
|
||||
if nil != err {
|
||||
t.Error("Copy file error: ", err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
118
util/go.go
118
util/go.go
|
@ -1,118 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
pathSeparator = string(os.PathSeparator) // OS-specific path separator
|
||||
pathListSeparator = string(os.PathListSeparator) // OS-specific path list separator
|
||||
)
|
||||
|
||||
type mygo struct{}
|
||||
|
||||
// Go utilities.
|
||||
var Go = mygo{}
|
||||
|
||||
func (*mygo) GetCrossPlatforms() []string {
|
||||
return []string{
|
||||
"darwin_amd64", "linux_amd64", "windows_amd64",
|
||||
"linux_arm", "darwin_386", "linux_386", "windows_386"}
|
||||
}
|
||||
|
||||
// GetAPIPath gets the Go source code path.
|
||||
//
|
||||
// 1. before Go 1.4: $GOROOT/src/pkg
|
||||
// 2. Go 1.4 and after: $GOROOT/src
|
||||
func (*mygo) GetAPIPath() string {
|
||||
ret := runtime.GOROOT() + "/src/pkg" // before Go 1.4
|
||||
if !File.IsExist(ret) {
|
||||
ret = runtime.GOROOT() + "/src" // Go 1.4 and after
|
||||
}
|
||||
|
||||
return filepath.FromSlash(path.Clean(ret))
|
||||
}
|
||||
|
||||
// IsAPI determines whether the specified path belongs to Go API.
|
||||
func (*mygo) IsAPI(path string) bool {
|
||||
apiPath := Go.GetAPIPath()
|
||||
|
||||
return strings.HasPrefix(filepath.FromSlash(path), apiPath)
|
||||
}
|
||||
|
||||
// GetGoFormats gets Go format tools. It may return ["gofmt", "goimports"].
|
||||
func (*mygo) GetGoFormats() []string {
|
||||
ret := []string{"gofmt"}
|
||||
|
||||
p := Go.GetExecutableInGOBIN("goimports")
|
||||
if File.IsExist(p) {
|
||||
ret = append(ret, "goimports")
|
||||
}
|
||||
|
||||
sort.Strings(ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// GetExecutableInGOBIN gets executable file under GOBIN path.
|
||||
//
|
||||
// The specified executable should not with extension, this function will append .exe if on Windows.
|
||||
func (*mygo) GetExecutableInGOBIN(executable string) string {
|
||||
if OS.IsWindows() {
|
||||
executable += ".exe"
|
||||
}
|
||||
|
||||
gopaths := filepath.SplitList(os.Getenv("GOPATH"))
|
||||
|
||||
for _, gopath := range gopaths {
|
||||
// $GOPATH/bin/$GOOS_$GOARCH/executable
|
||||
ret := gopath + pathSeparator + "bin" + pathSeparator +
|
||||
os.Getenv("GOOS") + "_" + os.Getenv("GOARCH") + pathSeparator + executable
|
||||
if File.IsExist(ret) {
|
||||
return ret
|
||||
}
|
||||
|
||||
// $GOPATH/bin/{runtime.GOOS}_{runtime.GOARCH}/executable
|
||||
ret = gopath + pathSeparator + "bin" + pathSeparator +
|
||||
runtime.GOOS + "_" + runtime.GOARCH + pathSeparator + executable
|
||||
if File.IsExist(ret) {
|
||||
return ret
|
||||
}
|
||||
|
||||
// $GOPATH/bin/executable
|
||||
ret = gopath + pathSeparator + "bin" + pathSeparator + executable
|
||||
if File.IsExist(ret) {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
// $GOBIN/executable
|
||||
gobin := os.Getenv("GOBIN")
|
||||
if "" != gobin {
|
||||
ret := gobin + pathSeparator + executable
|
||||
if File.IsExist(ret) {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
return "./" + executable
|
||||
}
|
101
util/go_test.go
101
util/go_test.go
|
@ -1,101 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
)
|
||||
|
||||
func TestGetCrossPlatforms(t *testing.T) {
|
||||
crossPlatforms := Go.GetCrossPlatforms()
|
||||
|
||||
if len(crossPlatforms) < 1 {
|
||||
t.Error("should have one platform at least")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAPIPath(t *testing.T) {
|
||||
apiPath := Go.GetAPIPath()
|
||||
|
||||
v := runtime.Version()[2:]
|
||||
|
||||
ver, err := version.NewVersion(v)
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
constraints, err := version.NewConstraint(">= 1.4")
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if constraints.Check(ver) {
|
||||
if !strings.HasSuffix(apiPath, "src") {
|
||||
t.Error("api path should end with \"src\"")
|
||||
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !strings.HasSuffix(apiPath, "pkg") {
|
||||
t.Error("api path should end with \"pkg\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsAPI(t *testing.T) {
|
||||
apiPath := Go.GetAPIPath()
|
||||
|
||||
if !Go.IsAPI(apiPath) {
|
||||
t.Error("api path root should belong to api path")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
root := "/root"
|
||||
|
||||
if Go.IsAPI(root) {
|
||||
t.Error("root should not belong to api path")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetGoFormats(t *testing.T) {
|
||||
formats := Go.GetGoFormats()
|
||||
|
||||
if len(formats) < 1 {
|
||||
t.Error("should have one go format tool [gofmt] at least")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetExecutableInGOBIN(t *testing.T) {
|
||||
bin := Go.GetExecutableInGOBIN("test")
|
||||
|
||||
if OS.IsWindows() {
|
||||
if !strings.HasSuffix(bin, ".exe") {
|
||||
t.Error("Executable binary should end with .exe")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/88250/gulu"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
)
|
||||
|
||||
// Logger
|
||||
var logger = gulu.Log.NewLogger(os.Stdout)
|
||||
|
||||
// HacPaiURL is the URL of HacPai community.
|
||||
const HacPaiURL = "https://ld246.com"
|
||||
|
||||
// HacPaiUserInfo returns HacPai community user info specified by the given access token.
|
||||
func HacPaiUserInfo(accessToken string) (ret map[string]interface{}) {
|
||||
result := map[string]interface{}{}
|
||||
response, data, errors := gorequest.New().TLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
|
||||
Post(HacPaiURL+"/user/ak").SendString("access_token="+accessToken).Timeout(7*time.Second).
|
||||
Set("User-Agent", "Pipe; +https://github.com/88250/wide").EndStruct(&result)
|
||||
if nil != errors || http.StatusOK != response.StatusCode {
|
||||
logger.Errorf("get community user info failed: %+v, %s", errors, data)
|
||||
return nil
|
||||
}
|
||||
if 0 != result["code"].(float64) {
|
||||
return nil
|
||||
}
|
||||
return result["data"].(map[string]interface{})
|
||||
}
|
45
util/net.go
45
util/net.go
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
// Package util includes common utilities.
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
type mynet struct{}
|
||||
|
||||
// Network utilities.
|
||||
var Net = mynet{}
|
||||
|
||||
// LocalIP gets the first NIC's IP address.
|
||||
func (*mynet) LocalIP() (string, error) {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
|
||||
if nil != err {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, address := range addrs {
|
||||
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||
if nil != ipnet.IP.To4() {
|
||||
return ipnet.IP.String(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("can't get local IP")
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLocalIP(t *testing.T) {
|
||||
ip, err := Net.LocalIP()
|
||||
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
t.Log(ip)
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/davidebianchi/go-jsonclient"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type oAuthAccessTokenReq struct {
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
Code string `json:"code"`
|
||||
GrantType string `json:"grant_type"`
|
||||
RedirectURI string `json:"redirect_uri"`
|
||||
}
|
||||
type oAuthAccessTokenResp struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
||||
func GetOAuthToken(oAuthAccessTokenURL, clientID, clientSecret, code, redirectURI string) (string, error) {
|
||||
u, err := url.Parse(oAuthAccessTokenURL)
|
||||
if err != nil {
|
||||
logger.Errorf(`failed to parse oAuthAccessTokenURL. error: %s`, err.Error())
|
||||
return ``, err
|
||||
}
|
||||
|
||||
client, err := jsonclient.New(jsonclient.Options{
|
||||
BaseURL: fmt.Sprintf(`%s://%s/`, u.Scheme, u.Host),
|
||||
})
|
||||
if err != nil {
|
||||
logger.Errorf(`failed to create access_token client. error: %s`, err.Error())
|
||||
return ``, err
|
||||
}
|
||||
|
||||
req, err := client.NewRequest(http.MethodPost, u.Path, &oAuthAccessTokenReq{
|
||||
ClientID: clientID,
|
||||
ClientSecret: clientSecret,
|
||||
Code: code,
|
||||
GrantType: `authorization_code`,
|
||||
RedirectURI: redirectURI,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Errorf(`failed to create access_token request. error: %s`, err.Error())
|
||||
return ``, err
|
||||
}
|
||||
|
||||
atResp := new(oAuthAccessTokenResp)
|
||||
|
||||
resp, err := client.Do(req, atResp)
|
||||
if err != nil {
|
||||
logger.Errorf(`failed to request access_token. error: %s`, err.Error())
|
||||
return ``, err
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
logger.Errorf(`access_token request return wrong code. code: %d, err_msg: %s`, resp.StatusCode, resp.Status)
|
||||
return ``, err
|
||||
}
|
||||
|
||||
return atResp.AccessToken, nil
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/davidebianchi/go-jsonclient"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type openIdUserInfoResp struct {
|
||||
Name string `json:"name"`
|
||||
GivenName string `json:"given_name"`
|
||||
FamilyName string `json:"family_name"`
|
||||
PreferredUsername string `json:"preferred_username"`
|
||||
Email string `json:"email"`
|
||||
Picture string `json:"picture"`
|
||||
}
|
||||
|
||||
func OpenIdUserInfo(openIdUserInfoURL, accessToken string) (map[string]any, error) {
|
||||
u, err := url.Parse(openIdUserInfoURL)
|
||||
if err != nil {
|
||||
logger.Errorf(`failed to parse openIdUserInfoURL. error: %s`, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := jsonclient.New(jsonclient.Options{
|
||||
BaseURL: fmt.Sprintf(`%s://%s/`, u.Scheme, u.Host),
|
||||
Headers: map[string]string{
|
||||
`Authorization`: fmt.Sprintf(`Bearer %s`, accessToken),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
logger.Errorf(`failed to create user_info client. error: %s`, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := client.NewRequest(http.MethodGet, u.Path, nil)
|
||||
if err != nil {
|
||||
logger.Errorf(`failed to create user_info request. error: %s`, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uiResp := new(openIdUserInfoResp)
|
||||
|
||||
resp, err := client.Do(req, uiResp)
|
||||
if err != nil {
|
||||
logger.Errorf(`failed to request user_info. error: %s`, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
logger.Errorf(`user_info request return wrong code. code: %d, err_msg: %s`, resp.StatusCode, resp.Status)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
`userId`: uiResp.PreferredUsername,
|
||||
`userName`: uiResp.Name,
|
||||
`avatar`: uiResp.Picture,
|
||||
}, nil
|
||||
}
|
100
util/os.go
100
util/os.go
|
@ -1,100 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type myos struct{}
|
||||
|
||||
// OS utilities.
|
||||
var OS = myos{}
|
||||
|
||||
// IsWindows determines whether current OS is Windows.
|
||||
func (*myos) IsWindows() bool {
|
||||
return "windows" == runtime.GOOS
|
||||
}
|
||||
|
||||
// Pwd gets the path of current working directory.
|
||||
func (*myos) Pwd() string {
|
||||
file, _ := exec.LookPath(os.Args[0])
|
||||
pwd, _ := filepath.Abs(file)
|
||||
|
||||
return filepath.Dir(pwd)
|
||||
}
|
||||
|
||||
// Home returns the home directory for the executing user.
|
||||
//
|
||||
// This uses an OS-specific method for discovering the home directory.
|
||||
// An error is returned if a home directory cannot be detected.
|
||||
func (*myos) Home() (string, error) {
|
||||
user, err := user.Current()
|
||||
if nil == err {
|
||||
return user.HomeDir, nil
|
||||
}
|
||||
|
||||
// cross compile support
|
||||
|
||||
if OS.IsWindows() {
|
||||
return homeWindows()
|
||||
}
|
||||
|
||||
// Unix-like system, so just assume Unix
|
||||
return homeUnix()
|
||||
}
|
||||
|
||||
func homeUnix() (string, error) {
|
||||
// First prefer the HOME environmental variable
|
||||
if home := os.Getenv("HOME"); home != "" {
|
||||
return home, nil
|
||||
}
|
||||
|
||||
// If that fails, try the shell
|
||||
var stdout bytes.Buffer
|
||||
cmd := exec.Command("sh", "-c", "eval echo ~$USER")
|
||||
cmd.Stdout = &stdout
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
result := strings.TrimSpace(stdout.String())
|
||||
if result == "" {
|
||||
return "", errors.New("blank output when reading home directory")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func homeWindows() (string, error) {
|
||||
drive := os.Getenv("HOMEDRIVE")
|
||||
path := os.Getenv("HOMEPATH")
|
||||
home := drive + path
|
||||
if drive == "" || path == "" {
|
||||
home = os.Getenv("USERPROFILE")
|
||||
}
|
||||
if home == "" {
|
||||
return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
|
||||
}
|
||||
|
||||
return home, nil
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsWiindows(t *testing.T) {
|
||||
goos := runtime.GOOS
|
||||
|
||||
if "windows" == goos && !OS.IsWindows() {
|
||||
t.Error("runtime.GOOS returns [windows]")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestPwd(t *testing.T) {
|
||||
if "" == OS.Pwd() {
|
||||
t.Error("Working directory should not be empty")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestHome(t *testing.T) {
|
||||
home, err := OS.Home()
|
||||
if nil != err {
|
||||
t.Error("Can not get user home")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
t.Log(home)
|
||||
}
|
104
util/panic.go
104
util/panic.go
|
@ -1,104 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/b3log/wide/log"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
var logger = log.NewLogger(os.Stdout)
|
||||
|
||||
var (
|
||||
dunno = []byte("???")
|
||||
centerDot = []byte("·")
|
||||
dot = []byte(".")
|
||||
slash = []byte("/")
|
||||
)
|
||||
|
||||
// Recover recovers a panic.
|
||||
func Recover() {
|
||||
if re := recover(); nil != re {
|
||||
stack := stack()
|
||||
logger.Errorf("PANIC RECOVERED: %v\n\t%s\n", re, stack)
|
||||
}
|
||||
}
|
||||
|
||||
// stack implements Stack, skipping 2 frames.
|
||||
func stack() []byte {
|
||||
buf := &bytes.Buffer{} // the returned data
|
||||
// As we loop, we open files and read them. These variables record the currently
|
||||
// loaded file.
|
||||
var lines [][]byte
|
||||
var lastFile string
|
||||
for i := 2; ; i++ { // Caller we care about is the user, 2 frames up
|
||||
pc, file, line, ok := runtime.Caller(i)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
// Print this much at least. If we can't find the source, it won't show.
|
||||
fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
|
||||
if file != lastFile {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
lines = bytes.Split(data, []byte{'\n'})
|
||||
lastFile = file
|
||||
}
|
||||
line-- // in stack trace, lines are 1-indexed but our array is 0-indexed
|
||||
fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// source returns a space-trimmed slice of the n'th line.
|
||||
func source(lines [][]byte, n int) []byte {
|
||||
if n < 0 || n >= len(lines) {
|
||||
return dunno
|
||||
}
|
||||
return bytes.Trim(lines[n], " \t")
|
||||
}
|
||||
|
||||
// function returns, if possible, the name of the function containing the PC.
|
||||
func function(pc uintptr) []byte {
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
return dunno
|
||||
}
|
||||
name := []byte(fn.Name())
|
||||
// The name includes the path name to the package, which is unnecessary
|
||||
// since the file name is already included. Plus, it has center dots.
|
||||
// That is, we see
|
||||
// runtime/debug.*T·ptrmethod
|
||||
// and want
|
||||
// *T.ptrmethod
|
||||
// Since the package path might contains dots (e.g. code.google.com/...),
|
||||
// we first remove the path prefix if there is one.
|
||||
if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
|
||||
name = name[lastslash+1:]
|
||||
}
|
||||
if period := bytes.Index(name, dot); period >= 0 {
|
||||
name = name[period+1:]
|
||||
}
|
||||
name = bytes.Replace(name, centerDot, dot, -1)
|
||||
return name
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRecover(t *testing.T) {
|
||||
defer Recover()
|
||||
|
||||
panic("test panic")
|
||||
}
|
47
util/rand.go
47
util/rand.go
|
@ -1,47 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type myrand struct{}
|
||||
|
||||
// Random utilities.
|
||||
var Rand = myrand{}
|
||||
|
||||
// String returns a random string ['a', 'z'] in the specified length
|
||||
func (*myrand) String(length int) string {
|
||||
bytes := make([]byte, length)
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
bytes[i] = byte(Rand.Int('a', 'z'))
|
||||
|
||||
time.Sleep(100 * time.Nanosecond)
|
||||
}
|
||||
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// Int returns a random integer in range [min, max].
|
||||
func (*myrand) Int(min int, max int) int {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
time.Sleep(100 * time.Nanosecond)
|
||||
|
||||
return min + rand.Intn(max-min)
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
r1 := Rand.String(16)
|
||||
r2 := Rand.String(16)
|
||||
|
||||
if r1 == r2 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
r1 := Rand.Int(0, 65535)
|
||||
r2 := Rand.Int(0, 65535)
|
||||
|
||||
if r1 == r2 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
115
util/ret.go
115
util/ret.go
|
@ -1,115 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/b3log/wide/log"
|
||||
)
|
||||
|
||||
// Logger.
|
||||
var retLogger = log.NewLogger(os.Stdout)
|
||||
|
||||
// Result.
|
||||
type Result struct {
|
||||
Succ bool `json:"succ"` // successful or not
|
||||
Code int `json:"code"` // return code
|
||||
Msg string `json:"msg"` // message
|
||||
Data interface{} `json:"data"` // data object
|
||||
}
|
||||
|
||||
// NewResult creates a result with Succ=true, Code=0, Msg="", Data=nil.
|
||||
func NewResult() *Result {
|
||||
return &Result{
|
||||
Succ: true,
|
||||
Code: 0,
|
||||
Msg: "",
|
||||
Data: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// RetResult writes HTTP response with "Content-Type, application/json".
|
||||
func RetResult(w http.ResponseWriter, r *http.Request, res *Result) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
data, err := json.Marshal(res)
|
||||
if err != nil {
|
||||
retLogger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
}
|
||||
|
||||
// RetGzResult writes HTTP response with "Content-Type, application/json" and "Content-Encoding, gzip".
|
||||
func RetGzResult(w http.ResponseWriter, r *http.Request, res *Result) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
|
||||
gz := gzip.NewWriter(w)
|
||||
err := json.NewEncoder(gz).Encode(res)
|
||||
if nil != err {
|
||||
retLogger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = gz.Close()
|
||||
if nil != err {
|
||||
retLogger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// RetJSON writes HTTP response with "Content-Type, application/json".
|
||||
func RetJSON(w http.ResponseWriter, r *http.Request, res map[string]interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
data, err := json.Marshal(res)
|
||||
if err != nil {
|
||||
retLogger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
}
|
||||
|
||||
// RetGzJSON writes HTTP response with "Content-Type, application/json" and "Content-Encoding, gzip".
|
||||
func RetGzJSON(w http.ResponseWriter, r *http.Request, res map[string]interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
|
||||
gz := gzip.NewWriter(w)
|
||||
err := json.NewEncoder(gz).Encode(res)
|
||||
if nil != err {
|
||||
retLogger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = gz.Close()
|
||||
if nil != err {
|
||||
retLogger.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
type str struct{}
|
||||
|
||||
// String utilities.
|
||||
var Str = str{}
|
||||
|
||||
// Contains determines whether the str is in the strs.
|
||||
func (*str) Contains(str string, strs []string) bool {
|
||||
for _, v := range strs {
|
||||
if v == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// LCS gets the longest common substring of s1 and s2.
|
||||
//
|
||||
// Refers to http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring.
|
||||
func (*str) LCS(s1 string, s2 string) string {
|
||||
var m = make([][]int, 1+len(s1))
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
m[i] = make([]int, 1+len(s2))
|
||||
}
|
||||
|
||||
longest := 0
|
||||
xLongest := 0
|
||||
|
||||
for x := 1; x < 1+len(s1); x++ {
|
||||
for y := 1; y < 1+len(s2); y++ {
|
||||
if s1[x-1] == s2[y-1] {
|
||||
m[x][y] = m[x-1][y-1] + 1
|
||||
if m[x][y] > longest {
|
||||
longest = m[x][y]
|
||||
xLongest = x
|
||||
}
|
||||
} else {
|
||||
m[x][y] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s1[xLongest-longest : xLongest]
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestContains(t *testing.T) {
|
||||
if !Str.Contains("123", []string{"123", "345"}) {
|
||||
t.Error("[\"123\", \"345\"] should contain \"123\"")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestLCS(t *testing.T) {
|
||||
str := Str.LCS("123456", "abc34def")
|
||||
|
||||
if "34" != str {
|
||||
t.Error("[\"123456\"] and [\"abc34def\"] should have the longest common substring [\"34\"]")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
230
util/zip.go
230
util/zip.go
|
@ -1,230 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
type myzip struct{}
|
||||
|
||||
// Zip utilities.
|
||||
var Zip = myzip{}
|
||||
|
||||
// ZipFile represents a zip file.
|
||||
type ZipFile struct {
|
||||
zipFile *os.File
|
||||
writer *zip.Writer
|
||||
}
|
||||
|
||||
// Create creates a zip file with the specified filename.
|
||||
func (*myzip) Create(filename string) (*ZipFile, error) {
|
||||
file, err := os.Create(filename)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ZipFile{zipFile: file, writer: zip.NewWriter(file)}, nil
|
||||
}
|
||||
|
||||
// Close closes the zip file writer.
|
||||
func (z *ZipFile) Close() error {
|
||||
err := z.writer.Close()
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
return z.zipFile.Close() // close the underlying writer
|
||||
}
|
||||
|
||||
// AddEntryN adds entries.
|
||||
func (z *ZipFile) AddEntryN(path string, names ...string) error {
|
||||
for _, name := range names {
|
||||
zipPath := filepath.Join(path, name)
|
||||
err := z.AddEntry(zipPath, name)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddEntry adds a entry.
|
||||
func (z *ZipFile) AddEntry(path, name string) error {
|
||||
fi, err := os.Stat(name)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
fh, err := zip.FileInfoHeader(fi)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
fh.Name = filepath.ToSlash(filepath.Clean(path))
|
||||
fh.Method = zip.Deflate // data compression algorithm
|
||||
|
||||
if fi.IsDir() {
|
||||
fh.Name = fh.Name + "/" // be care the ending separator
|
||||
}
|
||||
|
||||
entry, err := z.writer.CreateHeader(fh)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
if fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
file, err := os.Open(name)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.Copy(entry, file)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// AddDirectoryN adds directories.
|
||||
func (z *ZipFile) AddDirectoryN(path string, names ...string) error {
|
||||
for _, name := range names {
|
||||
err := z.AddDirectory(path, name)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDirectory adds a directory.
|
||||
func (z *ZipFile) AddDirectory(path, dirName string) error {
|
||||
files, err := ioutil.ReadDir(dirName)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
if 0 == len(files) {
|
||||
err := z.AddEntry(path, dirName)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
localPath := filepath.Join(dirName, file.Name())
|
||||
zipPath := filepath.Join(path, file.Name())
|
||||
|
||||
err = nil
|
||||
if file.IsDir() {
|
||||
err = z.AddDirectory(zipPath, localPath)
|
||||
} else {
|
||||
err = z.AddEntry(zipPath, localPath)
|
||||
}
|
||||
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cloneZipItem(f *zip.File, dest string) error {
|
||||
// create full directory path
|
||||
fileName := f.Name
|
||||
|
||||
if !utf8.ValidString(fileName) {
|
||||
data, err := ioutil.ReadAll(transform.NewReader(bytes.NewReader([]byte(fileName)), simplifiedchinese.GB18030.NewDecoder()))
|
||||
if nil == err {
|
||||
fileName = string(data)
|
||||
} else {
|
||||
logger.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
path := filepath.Join(dest, fileName)
|
||||
|
||||
err := os.MkdirAll(filepath.Dir(path), os.ModeDir|os.ModePerm)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
err = os.Mkdir(path, os.ModeDir|os.ModePerm)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// clone if item is a file
|
||||
|
||||
rc, err := f.Open()
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
defer rc.Close()
|
||||
|
||||
// use os.Create() since Zip don't store file permissions
|
||||
fileCopy, err := os.Create(path)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
defer fileCopy.Close()
|
||||
|
||||
_, err = io.Copy(fileCopy, rc)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unzip extracts a zip file specified by the zipFilePath to the destination.
|
||||
func (*myzip) Unzip(zipFilePath, destination string) error {
|
||||
r, err := zip.OpenReader(zipFilePath)
|
||||
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
|
||||
defer r.Close()
|
||||
|
||||
for _, f := range r.File {
|
||||
err = cloneZipItem(f, destination)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
149
util/zip_test.go
149
util/zip_test.go
|
@ -1,149 +0,0 @@
|
|||
// Copyright (c) 2014-present, b3log.org
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testDir = "../tmp"
|
||||
var packageName = filepath.Join(testDir, "test_zip")
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
zipFile, err := Zip.Create(packageName + ".zip")
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
zipFile.AddDirectoryN(".", ".")
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = zipFile.Close()
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnzip(t *testing.T) {
|
||||
err := Zip.Unzip(packageName+".zip", packageName)
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func _TestEmptyDir(t *testing.T) {
|
||||
dir1 := "/dir/subDir1"
|
||||
dir2 := "/dir/subDir2"
|
||||
|
||||
err := os.MkdirAll(packageName+dir1, os.ModeDir)
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = os.MkdirAll(packageName+dir2, os.ModeDir)
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Create(packageName + dir2 + "/file")
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
f.Close()
|
||||
|
||||
zipFile, err := Zip.Create(packageName + "/dir.zip")
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
zipFile.AddDirectoryN("dir", packageName+"/dir")
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = zipFile.Close()
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = Zip.Unzip(packageName+"/dir.zip", packageName+"/unzipDir")
|
||||
if nil != err {
|
||||
t.Error(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !File.IsExist(packageName+"/unzipDir") || !File.IsDir(packageName+"/unzipDir") {
|
||||
t.Error("Unzip failed")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !File.IsExist(packageName+"/unzipDir"+dir1) || !File.IsDir(packageName+"/unzipDir"+dir1) {
|
||||
t.Error("Unzip failed")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !File.IsExist(packageName+"/unzipDir"+dir2) || !File.IsDir(packageName+"/unzipDir"+dir2) {
|
||||
t.Error("Unzip failed")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !File.IsExist(packageName+"/unzipDir"+dir2+"/file") || File.IsDir(packageName+"/unzipDir"+dir2+"/file") {
|
||||
t.Error("Unzip failed")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
logger.Info(testDir)
|
||||
|
||||
retCode := m.Run()
|
||||
|
||||
// clean test data
|
||||
os.RemoveAll(testDir + "/test_zip")
|
||||
os.RemoveAll(testDir + "/util")
|
||||
os.RemoveAll(testDir + "/file.go")
|
||||
os.RemoveAll(testDir + "/test_zip.zip")
|
||||
|
||||
os.Exit(retCode)
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
<div class="item">
|
||||
<label>{{.i18n.project_address}}{{.i18n.colon}}</label>
|
||||
<a href="https://github.com/b3log/wide" target="_blank">github.com/b3log/wide</a><br/>
|
||||
<a href="https://github.com/88250/wide" target="_blank">github.com/88250/wide</a><br/>
|
||||
|
||||
<label>{{.i18n.dev_team}}{{.i18n.colon}}</label>
|
||||
<a href="https://github.com/b3log" target="_blank">B3log</a><br/>
|
||||
|
@ -35,7 +35,7 @@
|
|||
<a href="https://github.com/marijnh/CodeMirror" target="_blank">CodeMirror</a>
|
||||
<a href="https://github.com/zTree/zTree_v3" target="_blank">zTree</a>
|
||||
<a href="https://github.com/visualfc/liteide" target="_blank">LiteIDE</a>
|
||||
<a href="https://github.com/nsf/gocode" target="_blank">gocode</a>
|
||||
<a href="https://github.com/stamblerre/gocode" target="_blank">gocode</a>
|
||||
<a href="https://github.com/gorilla" target="_blank">Gorilla</a>
|
||||
<a href="https://docker.com" target="_blank">Docker</a>
|
||||
</li>
|
||||
|
@ -45,7 +45,7 @@
|
|||
<div class="space"></div>
|
||||
|
||||
<div class="item">
|
||||
<label><a href="https://github.com/b3log/wide/blob/master/TERMS.md" target="_blank">{{.i18n.terms}}</a> & {{.i18n.license}}{{.i18n.colon}}</label>
|
||||
<label><a href="https://github.com/88250/wide/blob/master/TERMS.md" target="_blank">{{.i18n.terms}}</a> & {{.i18n.license}}{{.i18n.colon}}</label>
|
||||
<pre class="license">
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{.i18n.wide}} - {{.i18n.wide_title}}</title>
|
||||
<meta name="keywords" content="Wide, Golang, IDE, Team, Cloud, B3log"/>
|
||||
<meta name="description" content="A Web-based Go IDE , do your development anytime, anywrhere."/>
|
||||
<meta name="keywords" content="Wide, Golang, IDE, Cloud, B3log"/>
|
||||
<meta name="description" content="A Web-based Go IDE , do your development anytime, anwhere."/>
|
||||
<meta name="author" content="B3log">
|
||||
<meta property="og:description" content="A Web-based Go IDE, do your development anytime, anywhere."/>
|
||||
{{if eq $.conf.RuntimeMode "dev"}}
|
||||
|
@ -31,6 +31,9 @@
|
|||
<link rel="stylesheet" href="/static/css/themes/{{.user.Theme}}.css?{{.conf.StaticResourceVersion}}" id="themesLink">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
{{if ne "" .conf.SiteStatCode}}
|
||||
{{.conf.SiteStatCode}}
|
||||
{{end}}
|
||||
</head>
|
||||
<body>
|
||||
<!-- menu bar -->
|
||||
|
@ -277,15 +280,10 @@
|
|||
<span>{{.i18n.test}}</span>
|
||||
</li>
|
||||
<li class="hr"></li>
|
||||
<li class="go-mod disabled" onclick="if (!$(this).hasClass('disabled')){menu.gomod()}">
|
||||
<span class="space"></span>
|
||||
<span>{{.i18n.gomod}}</span>
|
||||
</li>
|
||||
<li class="go-install disabled" onclick="if (!$(this).hasClass('disabled')){menu.goinstall()}">
|
||||
<span class="space"></span>
|
||||
<span>{{.i18n.goinstall}}</span>
|
||||
</li>
|
||||
<li class="hr"></li>
|
||||
<li class="go-vet disabled" onclick="if (!$(this).hasClass('disabled')){menu.govet()}">
|
||||
<span class="space"></span>
|
||||
<span>{{.i18n.govet}}</span>
|
||||
|
@ -300,11 +298,11 @@
|
|||
<span>{{.i18n.help}}</span>
|
||||
<div class="frame">
|
||||
<ul>
|
||||
<li onclick="window.open('https://hacpai.com/article/1538873544275')">
|
||||
<li onclick="window.open('https://ld246.com/article/1538873544275')">
|
||||
<span class="font-ico ico-book"></span>
|
||||
<span>{{.i18n.wide_doc}}</span>
|
||||
</li>
|
||||
<li onclick="window.open('https://github.com/b3log/wide/issues/new/choose')">
|
||||
<li onclick="window.open('https://github.com/88250/wide/issues/new/choose')">
|
||||
<span class="ico-report font-ico"></span>
|
||||
{{.i18n.issues}}
|
||||
</li>
|
||||
|
@ -327,6 +325,10 @@
|
|||
<span class="font-ico ico-about"></span>
|
||||
<span>{{.i18n.about}}</span>
|
||||
</li>
|
||||
<li onclick="window.open('https://ld246.com/sponsor')">
|
||||
<span class="space"></span>
|
||||
<span>{{.i18n.sponsor}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
|
@ -340,7 +342,7 @@
|
|||
src="{{.user.Avatar}}"
|
||||
title="{{.user.Name}}"/>
|
||||
<span class="font-ico ico-share"></span>
|
||||
<span onclick="window.open('https://github.com/b3log/wide')"
|
||||
<span onclick="window.open('https://github.com/88250/wide')"
|
||||
class="font-ico ico-github"></span>
|
||||
<div class="share-panel frame">
|
||||
<span title="Email" class="font-ico ico-email"></span>
|
||||
|
|
|
@ -4,11 +4,14 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>{{.i18n.wide}} - {{.i18n.keyboard_shortcuts}}</title>
|
||||
|
||||
<meta name="keywords" content="Wide, Golang, IDE, Team, Cloud, B3log, Keyboard Shortcuts"/>
|
||||
<meta name="description" content="A Web-based Go IDE , do your development anytime, anywrhere."/>
|
||||
<meta name="keywords" content="Wide, Golang, IDE, Cloud, B3log, Keyboard Shortcuts"/>
|
||||
<meta name="description" content="A Web-based Go IDE , do your development anytime, anywhere."/>
|
||||
<meta name="author" content="B3log">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
{{if ne "" .conf.SiteStatCode}}
|
||||
{{.conf.SiteStatCode}}
|
||||
{{end}}
|
||||
</head>
|
||||
<body>
|
||||
<h2>{{.i18n.editor}}</h2>
|
||||
|
|
|
@ -4,24 +4,27 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>{{.i18n.wide}} - {{.i18n.wide_title}}</title>
|
||||
|
||||
<meta name="keywords" content="Wide, Golang, IDE, Team, Cloud, B3log, Login"/>
|
||||
<meta name="description" content="A Web-based Go IDE , do your development anytime, anywrhere."/>
|
||||
<meta name="keywords" content="Wide, Golang, IDE, Cloud, B3log, Login"/>
|
||||
<meta name="description" content="A Web-based Go IDE , do your development anytime, anywhere."/>
|
||||
<meta name="author" content="B3log">
|
||||
|
||||
<link rel="stylesheet" href="/static/css/base.css?{{.conf.StaticResourceVersion}}">
|
||||
<link rel="stylesheet" href="/static/css/sign.css?{{.conf.StaticResourceVersion}}">
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico"/>
|
||||
{{if ne "" .conf.SiteStatCode}}
|
||||
{{.conf.SiteStatCode}}
|
||||
{{end}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="wrapper fn-clear">
|
||||
<a href="/login" rel="login" style="flex:1">
|
||||
<a href="{{$.conf.Server}}/login" rel="login" style="flex:1">
|
||||
<img title="A Web-based Go IDE" src="/static/images/wide-logo.png" class="logo"/></a>
|
||||
<ul>
|
||||
<li><a href="/playground" target="_blank" style="color: #cd504a">Play</a></li>
|
||||
<li><a rel="bookmark" href="https://github.com/b3log/wide" target="_blank">GitHub</a></li>
|
||||
<li><a rel="help" href="https://hacpai.com/article/1538873544275" target="_blank">{{.i18n.help}}</a></li>
|
||||
<li><a rel="bookmark" href="https://hacpai.com" target="_blank">{{.i18n.community}}</a></li>
|
||||
<li><a href="{{$.conf.Server}}/playground" target="_blank" style="color: #cd504a">Play</a></li>
|
||||
<li><a rel="bookmark" href="https://github.com/88250/wide" target="_blank">GitHub</a></li>
|
||||
<li><a rel="help" href="https://ld246.com/article/1538873544275" target="_blank">{{.i18n.help}}</a></li>
|
||||
<li><a rel="bookmark" href="https://ld246.com" target="_blank">{{.i18n.community}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -31,19 +34,23 @@
|
|||
<h2>Hello, 世界</h2>
|
||||
<h3>Coding with Go on the Wide way.</h3>
|
||||
</div>
|
||||
<div class="form fn-right">
|
||||
<div style="text-align: center"><a href="https://hacpai.com/article/1558097702072" target="_blank">2019-05-17 关于账号迁移的公告</a></div>
|
||||
<div class="login__github oauth"></div>
|
||||
<img style="display: none" src="/static/images/github.gif"/>
|
||||
<button class="btn oauth">登录 GitHub 账号后即可开始使用</button>
|
||||
<div class="desc">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox"/>
|
||||
是否愿意在 GitHub 上收藏该<a href="https://github.com/b3log/wide" target="_blank">项目</a>、关注<a
|
||||
href="https://github.com/88250" target="_blank">开发者</a>并加入 <a
|
||||
href="https://github.com/b3log" target="_blank">B3log
|
||||
开源组织</a>
|
||||
</label>
|
||||
<div class="form fn-right start">
|
||||
<a href="{{$.conf.Server}}/login/redirect">
|
||||
<svg class="login__icon" viewBox="0 0 32 32">
|
||||
<path fill="#d23f31" style="fill: var(--color1, #d23f31)"
|
||||
d="M5.787 17.226h17.033l5.954 9.528c0.47 0.752 0.003 1.361-1.042 1.361h-15.141z"></path>
|
||||
<path d="M10.74 3.927h17.033c1.045 0 1.512 0.609 1.042 1.361l-5.954 9.528h-19.872l6.379-10.209c0.235-0.376 0.849-0.681 1.372-0.681z"></path>
|
||||
<path d="M2.953 17.226h2.839l6.804 10.889h-1.892c-0.523 0-1.137-0.305-1.372-0.681z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<div class="start__aciton">
|
||||
<a href="{{$.conf.Server}}/login/redirect" class="btn">登录链滴社区账号后即可开始使用</a>
|
||||
<span> </span>
|
||||
<a href="https://ld246.com/article/1576294445994" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 32 32">
|
||||
<path d="M19.652 25v6c0 0.55-0.45 1-1 1h-6c-0.55 0-1-0.45-1-1v-6c0-0.55 0.45-1 1-1h6c0.55 0 1 0.45 1 1zM27.552 10c0 4.75-3.225 6.575-5.6 7.9-1.475 0.85-2.4 2.575-2.4 3.3v0c0 0.55-0.425 1.2-1 1.2h-6c-0.55 0-0.9-0.85-0.9-1.4v-1.125c0-3.025 3-5.625 5.2-6.625 1.925-0.875 2.725-1.7 2.725-3.3 0-1.4-1.825-2.65-3.85-2.65-1.125 0-2.15 0.35-2.7 0.725-0.6 0.425-1.2 1.025-2.675 2.875-0.2 0.25-0.5 0.4-0.775 0.4-0.225 0-0.425-0.075-0.625-0.2l-4.1-3.125c-0.425-0.325-0.525-0.875-0.25-1.325 2.7-4.475 6.5-6.65 11.6-6.65 5.35 0 11.35 4.275 11.35 10z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -53,11 +60,5 @@
|
|||
Ver {{.ver}}, © {{.year}} <a rel="copyright" href="https://b3log.org" target="_blank">B3log 开源</a>
|
||||
</span>
|
||||
</div>
|
||||
<script type="text/javascript" src="/static/js/lib/jquery-2.1.1.min.js"></script>
|
||||
<script>
|
||||
$('.oauth').click(function () {
|
||||
window.location.href = '/oauth/github/redirect?state=' + ($('input').prop('checked') ? '0' : '1')
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{.i18n.wide}} - {{.i18n.wide_title}}</title>
|
||||
|
||||
<meta name="keywords" content="Wide, Golang, IDE, Team, Cloud, B3log, Playground"/>
|
||||
<meta name="description" content="A Web-based Go IDE , do your development anytime, anywrhere."/>
|
||||
<meta name="keywords" content="Wide, Golang, IDE, Cloud, B3log, Playground"/>
|
||||
<meta name="description" content="A Web-based Go IDE , do your development anytime, anywhere."/>
|
||||
<meta name="author" content="B3log">
|
||||
|
||||
<link rel="stylesheet" href="/static/js/lib/codemirror-{{.codeMirrorVer}}/codemirror.css?{{.conf.StaticResourceVersion}}">
|
||||
<link rel="stylesheet"
|
||||
href="/static/js/lib/codemirror-{{.codeMirrorVer}}/codemirror.css?{{.conf.StaticResourceVersion}}">
|
||||
<link rel="stylesheet" href="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/hint/show-hint.css">
|
||||
<link rel="stylesheet" href="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/fold/foldgutter.css">
|
||||
<link rel="stylesheet" href="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/dialog/dialog.css">
|
||||
<link rel="stylesheet" href="{{$.conf.Server}}/static/js/overwrite/codemirror/theme/wide.css?{{.conf.StaticResourceVersion}}">
|
||||
<link rel="stylesheet"
|
||||
href="{{$.conf.Server}}/static/js/overwrite/codemirror/theme/wide.css?{{.conf.StaticResourceVersion}}">
|
||||
|
||||
<link rel="stylesheet" href="/static/css/dialog.css?{{.conf.StaticResourceVersion}}">
|
||||
<link rel="stylesheet" href="/static/css/base.css?{{.conf.StaticResourceVersion}}">
|
||||
|
@ -23,10 +25,13 @@
|
|||
<link rel="stylesheet" href="/static/css/side.css?{{.conf.StaticResourceVersion}}">
|
||||
<link rel="stylesheet" href="/static/css/playground.css?{{.conf.StaticResourceVersion}}">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="header menu fn-clear">
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico"/>
|
||||
{{if ne "" .conf.SiteStatCode}}
|
||||
{{.conf.SiteStatCode}}
|
||||
{{end}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="header menu fn-clear">
|
||||
<ul class="fn-left">
|
||||
<li>
|
||||
<a href="/" target="_blank">
|
||||
|
@ -44,11 +49,16 @@
|
|||
<li>
|
||||
<button class="btn-white btn" id="share" onclick="playground.share();">{{.i18n.share}}</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="btn btn-blue" onclick="window.open('https://ld246.com/sponsor')">
|
||||
{{.i18n.sponsor}}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="fn-right">
|
||||
<span class="font-ico ico-about" onclick='$("#dialogAbout").dialog("open");'></span>
|
||||
<span class="font-ico ico-share"></span>
|
||||
<span onclick="window.open('https://github.com/b3log/wide')"
|
||||
<span onclick="window.open('https://github.com/88250/wide')"
|
||||
class="font-ico ico-github"></span>
|
||||
<div class="share-panel frame" style="display: none;">
|
||||
<span title="Email" class="font-ico ico-email"></span>
|
||||
|
@ -58,9 +68,9 @@
|
|||
<span title="QQ空间" class="font-ico ico-qqz"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fn-clear">
|
||||
<div class="fn-left" id="editorDivWrap">
|
||||
</div>
|
||||
<div class="main">
|
||||
<div id="editorDivWrap">
|
||||
<div id="editorDiv">
|
||||
<textarea rows="20" id='editor' class="fn-none">{{.code}}</textarea>
|
||||
</div>
|
||||
|
@ -68,17 +78,18 @@
|
|||
<div id="output" class="output"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fn-right" id="goNews"></div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div id="goNews"></div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<span class="wrapper">
|
||||
Ver {{.ver}}, © {{.year}} <a rel="copyright" href="https://b3log.org" target="_blank">B3log 开源</a>
|
||||
Ver {{.ver}}, © {{.year}} <a rel="copyright" href="https://b3log.org"
|
||||
target="_blank">B3log 开源</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="dialogAbout" class="fn-none"></div>
|
||||
<div id="dialogShare" class="fn-none"></div>
|
||||
<script>
|
||||
<div id="dialogAbout" class="fn-none"></div>
|
||||
<div id="dialogShare" class="fn-none"></div>
|
||||
<script>
|
||||
var channelScheme = -1 < window.location.protocol.indexOf("https") ? "wss":"ws";
|
||||
var channel = channelScheme + "://" + window.location.hostname + ":" + window.location.port;
|
||||
var config = {
|
||||
|
@ -93,35 +104,36 @@
|
|||
};
|
||||
return ret;
|
||||
}
|
||||
</script>
|
||||
|
||||
</script>
|
||||
<script type="text/javascript" src="/static/js/lib/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/reconnecting-websocket.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/Autolinker.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/codemirror.min.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/selection/active-line.js"></script>
|
||||
<script type="text/javascript" src="/static/js/overwrite/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/hint/anyword-hint.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/display/rulers.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/edit/closetag.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/search/match-highlighter.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/fold/foldgutter.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/fold/comment-fold.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/mode/loadmode.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/mode/meta.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/mode/go/go.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/static/js/lib/jquery-2.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/reconnecting-websocket.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/codemirror.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/selection/active-line.js"></script>
|
||||
<script type="text/javascript" src="/static/js/overwrite/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/hint/anyword-hint.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/display/rulers.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/edit/closetag.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/search/match-highlighter.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/fold/foldgutter.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/fold/comment-fold.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/mode/loadmode.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/mode/meta.js"></script>
|
||||
<script type="text/javascript" src="/static/js/lib/codemirror-{{.codeMirrorVer}}/mode/go/go.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/static/js/dialog.js?{{.conf.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="/static/js/menu.js?{{.conf.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="/static/js/playground.js?{{.conf.StaticResourceVersion}}"></script>
|
||||
</body>
|
||||
<script type="text/javascript" src="/static/js/dialog.js?{{.conf.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="/static/js/menu.js?{{.conf.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="/static/js/playground.js?{{.conf.StaticResourceVersion}}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
<span>{{.workspace}}</span>
|
||||
</li>
|
||||
<li class="border">
|
||||
<label><a href="https://hacpai.com/article/1538873544275" target="_blank">{{.i18n.user_guide}}</a></label> &
|
||||
<label><a href="https://hacpai.com/article/1538876422995" target="_blank">{{.i18n.dev_guide}}</a></label>
|
||||
<label><a href="https://ld246.com/article/1538873544275" target="_blank">{{.i18n.user_guide}}</a></label> &
|
||||
<label><a href="https://ld246.com/article/1538876422995" target="_blank">{{.i18n.dev_guide}}</a></label>
|
||||
</li>
|
||||
<li>
|
||||
<label>{{.i18n.current_ver}}{{.i18n.colon}}</label>
|
||||
{{.ver}}<br/>
|
||||
<label>{{.i18n.project_address}}{{.i18n.colon}}</label>
|
||||
<a href="https://github.com/b3log/wide" target="_blank">github.com/b3log/wide</a><br/>
|
||||
<a href="https://github.com/88250/wide" target="_blank">github.com/88250/wide</a><br/>
|
||||
<label>{{.i18n.dev_team}}{{.i18n.colon}}</label>
|
||||
<a href="https://github.com/b3log/b3log-solo/wiki/About_us" target="_blank">B3log</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue