forked from x/ContextOS
mac pro tcp
This commit is contained in:
parent
5f7d55da1a
commit
15d4da1b18
@ -10,4 +10,5 @@ source etc/local.shy
|
||||
alias import nfs
|
||||
alias send send
|
||||
alias dial dial
|
||||
alias pwd pwd
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,13 @@
|
||||
package nfs // {{{
|
||||
// }}}
|
||||
import ( // {{{
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"contexts"
|
||||
"encoding/json"
|
||||
"github.com/nsf/termbox-go"
|
||||
"github.com/skip2/go-qrcode"
|
||||
"net"
|
||||
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/nsf/termbox-go"
|
||||
"github.com/skip2/go-qrcode"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
@ -22,10 +20,6 @@ import ( // {{{
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// }}}
|
||||
|
||||
var FileNotExist = errors.New("file not exist")
|
||||
|
||||
type NFS struct {
|
||||
in *os.File
|
||||
out *os.File
|
||||
@ -35,7 +29,7 @@ type NFS struct {
|
||||
height int
|
||||
|
||||
paths []string
|
||||
io net.Conn
|
||||
io io.ReadWriter
|
||||
|
||||
send chan *ctx.Message
|
||||
recv chan *ctx.Message
|
||||
@ -50,7 +44,7 @@ type NFS struct {
|
||||
*ctx.Context
|
||||
}
|
||||
|
||||
func (nfs *NFS) open(name string) (*os.File, error) { // {{{
|
||||
func (nfs *NFS) open(name string) (*os.File, error) {
|
||||
if path.IsAbs(name) {
|
||||
nfs.Message.Log("info", "open %s", name)
|
||||
return os.Open(name)
|
||||
@ -64,9 +58,7 @@ func (nfs *NFS) open(name string) (*os.File, error) { // {{{
|
||||
nfs.Log("info", "open %s", name)
|
||||
return os.Open(name)
|
||||
}
|
||||
|
||||
// }}}
|
||||
func dir(m *ctx.Message, name string, level int, deep bool, fields []string) { // {{{
|
||||
func dir(m *ctx.Message, name string, level int, deep bool, fields []string) {
|
||||
back, e := os.Getwd()
|
||||
m.Assert(e)
|
||||
os.Chdir(name)
|
||||
@ -155,9 +147,7 @@ func dir(m *ctx.Message, name string, level int, deep bool, fields []string) { /
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) insert(rest []rune, letters []rune) []rune { // {{{
|
||||
func (nfs *NFS) insert(rest []rune, letters []rune) []rune {
|
||||
n := len(rest)
|
||||
l := len(letters)
|
||||
rest = append(rest, letters...)
|
||||
@ -169,18 +159,13 @@ func (nfs *NFS) insert(rest []rune, letters []rune) []rune { // {{{
|
||||
}
|
||||
return rest
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
func (nfs *NFS) escape(form string, args ...interface{}) *NFS { // {{{
|
||||
func (nfs *NFS) escape(form string, args ...interface{}) *NFS {
|
||||
if !nfs.Caps("windows") {
|
||||
fmt.Fprintf(nfs.out, "\033[%s", fmt.Sprintf(form, args...))
|
||||
}
|
||||
return nfs
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) color(str string, attr ...int) *NFS { // {{{
|
||||
func (nfs *NFS) color(str string, attr ...int) *NFS {
|
||||
if !nfs.Confs("color") {
|
||||
fmt.Fprint(nfs.out, str)
|
||||
return nfs
|
||||
@ -205,9 +190,7 @@ func (nfs *NFS) color(str string, attr ...int) *NFS { // {{{
|
||||
nfs.escape("0m")
|
||||
return nfs
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) print(str string) bool { // {{{
|
||||
func (nfs *NFS) print(str string) bool {
|
||||
ls := strings.Split(str, "\n")
|
||||
for i, l := range ls {
|
||||
rest := ""
|
||||
@ -237,8 +220,7 @@ func (nfs *NFS) print(str string) bool { // {{{
|
||||
return true
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) prompt(arg ...string) string { // {{{
|
||||
func (nfs *NFS) prompt(arg ...string) string {
|
||||
ps := nfs.Option("prompt")
|
||||
if nfs.Caps("windows") {
|
||||
nfs.color(ps)
|
||||
@ -269,10 +251,7 @@ func (nfs *NFS) prompt(arg ...string) string { // {{{
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
func (nfs *NFS) zone(buf []string, top, height int) (row, col int) { // {{{
|
||||
func (nfs *NFS) zone(buf []string, top, height int) (row, col int) {
|
||||
row, col = len(buf)-1, 0
|
||||
for i := nfs.Capi("cursor_pos"); i > top-1; {
|
||||
if i -= len(buf[row]) / nfs.width; len(buf[row])%nfs.width > 0 {
|
||||
@ -286,9 +265,7 @@ func (nfs *NFS) zone(buf []string, top, height int) (row, col int) { // {{{
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) page(buf []string, row, col, top, height int, status bool) { // {{{
|
||||
func (nfs *NFS) page(buf []string, row, col, top, height int, status bool) {
|
||||
nfs.escape("2J").escape("H")
|
||||
begin := row
|
||||
|
||||
@ -313,9 +290,7 @@ func (nfs *NFS) page(buf []string, row, col, top, height int, status bool) { //
|
||||
nfs.escape("E").color(fmt.Sprintf("pages: %d/%d", begin, len(nfs.pages)), nfs.Confi("statusfgcolor"), nfs.Confi("statusbgcolor"))
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) View(buf []string, top int, height int) { // {{{
|
||||
func (nfs *NFS) View(buf []string, top int, height int) {
|
||||
|
||||
row, col := nfs.zone(buf, top, height)
|
||||
nfs.page(buf, row, col, top, height, true)
|
||||
@ -368,9 +343,7 @@ func (nfs *NFS) View(buf []string, top int, height int) { // {{{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) Read(p []byte) (n int, err error) { // {{{
|
||||
func (nfs *NFS) Read(p []byte) (n int, err error) {
|
||||
if nfs.Caps("windows") || !nfs.Caps("termbox") {
|
||||
return nfs.in.Read(p)
|
||||
}
|
||||
@ -562,9 +535,7 @@ func (nfs *NFS) Read(p []byte) (n int, err error) { // {{{
|
||||
return
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
func (nfs *NFS) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
|
||||
func (nfs *NFS) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
|
||||
if len(arg) > 0 && (arg[0] == "scan" || arg[0] == "open" || arg[0] == "append") {
|
||||
c.Caches = map[string]*ctx.Cache{
|
||||
"pos": &ctx.Cache{Name: "pos", Value: "0", Help: "pos"},
|
||||
@ -589,16 +560,12 @@ func (nfs *NFS) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
|
||||
return s
|
||||
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||
func (nfs *NFS) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
||||
nfs.Message = m
|
||||
nfs.width, nfs.height = 1, 1
|
||||
return nfs
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool {
|
||||
nfs.Message = m
|
||||
if len(arg) > 0 && arg[0] == "scan" {
|
||||
nfs.Caches["windows"] = &ctx.Cache{Name: "windows", Value: "false", Help: "termbox"}
|
||||
@ -702,7 +669,7 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
}
|
||||
|
||||
m.Cap("stream", m.Option("stream"))
|
||||
nfs.io = m.Optionv("io").(net.Conn)
|
||||
nfs.io = m.Optionv("io").(io.ReadWriter)
|
||||
nfs.hand = map[int]*ctx.Message{}
|
||||
nfs.send = make(chan *ctx.Message, 10)
|
||||
nfs.recv = make(chan *ctx.Message, 10)
|
||||
@ -744,10 +711,11 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
}()
|
||||
|
||||
go func() { //接收消息队列
|
||||
bio := bufio.NewScanner(nfs.io)
|
||||
var e error
|
||||
var msg *ctx.Message
|
||||
for head, body := "", ""; bio.Scan(); {
|
||||
head, body := "", ""
|
||||
|
||||
for bio := bufio.NewScanner(nfs.io); bio.Scan(); {
|
||||
if msg == nil {
|
||||
msg = m.Sess("target")
|
||||
}
|
||||
@ -755,9 +723,9 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
msg.Meta = map[string][]string{}
|
||||
}
|
||||
line := bio.Text()
|
||||
m.Log("recv", "(%s) %s", head, line)
|
||||
m.Capi("nread", len(line)+1)
|
||||
if len(line) == 0 {
|
||||
|
||||
if head == "detail" {
|
||||
m.Log("info", "%d recv: %v %v %v", m.Capi("nrecv", 1), msg.Meta[head], msg.Meta[body], msg.Meta)
|
||||
msg.Option("recv_code", m.Cap("nrecv"))
|
||||
@ -768,7 +736,7 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
h.Copy(msg, "result").Copy(msg, "append")
|
||||
h.Remote <- true
|
||||
}
|
||||
msg = nil
|
||||
msg, head, body = nil, "", "append"
|
||||
continue
|
||||
}
|
||||
|
||||
@ -799,9 +767,7 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (nfs *NFS) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||
func (nfs *NFS) Close(m *ctx.Message, arg ...string) bool {
|
||||
return false
|
||||
switch nfs.Context {
|
||||
case m.Target():
|
||||
@ -813,17 +779,12 @@ func (nfs *NFS) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||
nfs.out.Close()
|
||||
nfs.out = nil
|
||||
}
|
||||
if nfs.io != nil {
|
||||
nfs.io.Close()
|
||||
nfs.io = nil
|
||||
}
|
||||
case m.Source():
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
var FileNotExist = errors.New("file not exist")
|
||||
var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
Caches: map[string]*ctx.Cache{
|
||||
"nfile": &ctx.Cache{Name: "nfile", Value: "-1", Help: "已经打开的文件数量"},
|
||||
@ -831,11 +792,11 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
Configs: map[string]*ctx.Config{
|
||||
"pscolor": &ctx.Config{Name: "pscolor", Value: "2", Help: "pscolor"},
|
||||
"nfs_name": &ctx.Config{Name: "nfs_name", Value: "file", Help: "默认模块命名", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
|
||||
if len(arg) > 0 { // {{{
|
||||
if len(arg) > 0 {
|
||||
return arg[0]
|
||||
}
|
||||
return fmt.Sprintf("%s%d", x.Value, m.Capi("nfile", 1))
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"nfs_help": &ctx.Config{Name: "nfs_help", Value: "file", Help: "默认模块帮助"},
|
||||
|
||||
@ -865,7 +826,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
Name: "paths [add path]|[del index]|[set index path]|[index]",
|
||||
Help: "设置文件搜索路径, add: 添加目录, del: 删除目录, set: 修改目录,index: 目录序号, path: 目录名",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) { // {{{
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) {
|
||||
if len(arg) == 0 {
|
||||
for i, v := range nfs.paths {
|
||||
m.Echo("%d: %s\n", i, v)
|
||||
@ -892,13 +853,13 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
m.Echo("%d: %s\n", i, nfs.paths[i])
|
||||
}
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"scan": &ctx.Command{
|
||||
Name: "scan filename [nfs_name [nfs_help]]",
|
||||
Help: "扫描文件, filename: 文件名, nfs_name: 模块名, nfs_help: 模块帮助",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) { // {{{
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) {
|
||||
if arg[0] == "stdio" {
|
||||
m.Optionv("in", os.Stdin)
|
||||
m.Optionv("out", os.Stdout)
|
||||
@ -909,13 +870,13 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
}
|
||||
|
||||
m.Start(m.Confx("nfs_name", arg, 1), m.Confx("nfs_help", arg, 2), key, arg[0])
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"history": &ctx.Command{
|
||||
Name: "history [save|load filename [lines [pos]]] [find|search key]",
|
||||
Help: "扫描记录, save: 保存记录, load: 加载记录, filename: 文件名, lines: 加载或保存记录数量, pos: 加载或保存的起始位置, find: 查找记录, search: 搜索记录, key: 查找或搜索的参数",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) { // {{{
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) {
|
||||
if len(arg) == 0 {
|
||||
for i, v := range nfs.history {
|
||||
m.Echo("%d: %s\n", i, v)
|
||||
@ -1000,34 +961,34 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
m.Echo(nfs.history[i])
|
||||
}
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"open": &ctx.Command{
|
||||
Name: "open filename [nfs_name [nfs_help]]",
|
||||
Help: "打开文件, filename: 文件名, nfs_name: 模块名, nfs_help: 模块帮助",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if m.Has("io") { // {{{
|
||||
if m.Has("io") {
|
||||
} else if f, e := os.OpenFile(arg[0], os.O_RDWR|os.O_CREATE, os.ModePerm); m.Assert(e) {
|
||||
m.Put("option", "in", f).Put("option", "out", f)
|
||||
}
|
||||
m.Start(m.Confx("nfs_name", arg, 1), m.Confx("nfs_help", arg, 2), "open", arg[0])
|
||||
m.Echo(m.Target().Name)
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"append": &ctx.Command{
|
||||
Name: "append filename [nfs_name [nfs_help]]",
|
||||
Help: "打开文件, filename: 文件名, nfs_name: 模块名, nfs_help: 模块帮助",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if m.Has("io") { // {{{
|
||||
if m.Has("io") {
|
||||
} else if f, e := os.OpenFile(arg[0], os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm); m.Assert(e) {
|
||||
m.Put("option", "in", f).Put("option", "out", f)
|
||||
}
|
||||
m.Start(m.Confx("nfs_name", arg, 1), m.Confx("nfs_help", arg, 2), "append", arg[0])
|
||||
m.Echo(m.Target().Name)
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"read": &ctx.Command{Name: "read [buf_size [pos]]", Help: "读取文件, buf_size: 读取大小, pos: 读取位置", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) && nfs.in != nil { // {{{
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) && nfs.in != nil {
|
||||
n, e := strconv.Atoi(m.Confx("buf_size", arg, 0))
|
||||
m.Assert(e)
|
||||
|
||||
@ -1045,10 +1006,10 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
if m.Capi("pos", n); n == 0 {
|
||||
m.Cap("pos", "0")
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"write": &ctx.Command{Name: "write string [pos]", Help: "写入文件, string: 写入内容, pos: 写入位置", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) && nfs.out != nil { // {{{
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) && nfs.out != nil {
|
||||
if len(arg) > 1 {
|
||||
m.Cap("pos", arg[1])
|
||||
}
|
||||
@ -1066,10 +1027,10 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
}
|
||||
|
||||
m.Echo(m.Cap("pos"))
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"load": &ctx.Command{Name: "load file [buf_size [pos]]", Help: "加载文件, buf_size: 加载大小, pos: 加载位置", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if f, e := os.Open(arg[0]); m.Assert(e) { // {{{
|
||||
if f, e := os.Open(arg[0]); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
pos := 0
|
||||
@ -1087,34 +1048,34 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
m.Log("info", "read %d", l)
|
||||
m.Echo(string(buf[:l]))
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"save": &ctx.Command{Name: "save file string...", Help: "保存文件, file: 保存的文件, string: 保存的内容", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if f, e := os.Create(arg[0]); m.Assert(e) { // {{{
|
||||
if f, e := os.Create(arg[0]); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
for _, v := range arg[1:] {
|
||||
fmt.Fprint(f, v)
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"print": &ctx.Command{Name: "print file string...", Help: "输出文件, file: 输出的文件, string: 输出的内容", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if f, e := os.OpenFile(arg[0], os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666); m.Assert(e) { // {{{
|
||||
if f, e := os.OpenFile(arg[0], os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
for _, v := range arg[1:] {
|
||||
fmt.Fprint(f, v)
|
||||
}
|
||||
fmt.Fprint(f, "\n")
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"genqr": &ctx.Command{Name: "genqr [qr_size size] filename string...", Help: "生成二维码图片, qr_size: 图片大小, filename: 文件名, string: 输出内容", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if size, e := strconv.Atoi(m.Confx("qr_size")); m.Assert(e) { // {{{
|
||||
if size, e := strconv.Atoi(m.Confx("qr_size")); m.Assert(e) {
|
||||
qrcode.WriteFile(strings.Join(arg[1:], ""), qrcode.Medium, size, arg[0])
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"json": &ctx.Command{Name: "json [key value]...", Help: "生成格式化内容, key: 参数名, value: 参数值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if len(arg) == 1 { // {{{
|
||||
if len(arg) == 1 {
|
||||
var data interface{}
|
||||
e := json.Unmarshal([]byte(arg[0]), &data)
|
||||
m.Assert(e)
|
||||
@ -1156,10 +1117,10 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
buf, e := json.Marshal(data)
|
||||
m.Assert(e)
|
||||
m.Echo(string(buf))
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"pwd": &ctx.Command{Name: "pwd", Help: "查看当前路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if m.Options("dir") { // {{{
|
||||
if m.Options("dir") {
|
||||
m.Echo(m.Option("dir"))
|
||||
m.Add("append", "hi", "hello")
|
||||
m.Add("append", "he", "hello")
|
||||
@ -1172,7 +1133,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
}
|
||||
wd, e := os.Getwd()
|
||||
m.Assert(e)
|
||||
m.Echo(wd) // }}}
|
||||
m.Echo(wd)
|
||||
m.Append("hi", "hello")
|
||||
}},
|
||||
"dir": &ctx.Command{
|
||||
@ -1180,7 +1141,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
Help: "查看目录, dir: 目录名, dir_info: 显示统计信息, dir_name: 文件名类型, dir_type: 文件类型, sort_field: 排序字段, sort_order: 排序类型",
|
||||
Form: map[string]int{"dir_field": 1, "dir_deep": 1, "dir_info": 1, "dir_name": 1, "dir_type": 1, "sort_field": 1, "sort_order": 1},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
d := "./" + m.Option("dir") // {{{
|
||||
d := "./" + m.Option("dir")
|
||||
if len(arg) > 0 {
|
||||
d = arg[0]
|
||||
}
|
||||
@ -1224,14 +1185,14 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
for _, v := range info {
|
||||
m.Echo("%s: %s\n", v, m.Option(v))
|
||||
}
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"git": &ctx.Command{
|
||||
Name: "git branch|status|diff|log|info arg... [dir path]...",
|
||||
Help: "版本控制, branch: 分支管理, status: 查看状态, info: 查看分支与状态, dir: 指定路径",
|
||||
Form: map[string]int{"dir": 1, "git_info": 1, "git_log": 1, "git_log_form": 1},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if len(arg) == 0 { // {{{
|
||||
if len(arg) == 0 {
|
||||
arg = []string{"info"}
|
||||
}
|
||||
cmds := []string{arg[0]}
|
||||
@ -1354,7 +1315,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
m.Copy(msg, "result").Copy(msg, "append")
|
||||
m.Echo("\n")
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
|
||||
"listen": &ctx.Command{Name: "listen args...", Help: "启动文件服务, args: 参考tcp模块, listen命令的参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
@ -1370,7 +1331,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
})
|
||||
}, m.Meta["detail"])
|
||||
}
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"dial": &ctx.Command{Name: "dial args...", Help: "连接文件服务, args: 参考tcp模块, dial命令的参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if _, ok := m.Target().Server.(*NFS); m.Assert(ok) { //{{{
|
||||
@ -1385,14 +1346,14 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
})
|
||||
}, m.Meta["detail"])
|
||||
}
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"send": &ctx.Command{Name: "send [file] args...", Help: "连接文件服务, args: 参考tcp模块, dial命令的参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) && nfs.io != nil { // {{{
|
||||
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) && nfs.io != nil {
|
||||
m.Remote = make(chan bool, 1)
|
||||
nfs.send <- m
|
||||
<-m.Remote
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
package ssh // {{{
|
||||
// }}}
|
||||
import ( // {{{
|
||||
"contexts"
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"contexts"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// }}}
|
||||
|
||||
type SSH struct {
|
||||
nfs *ctx.Context
|
||||
peer map[string]*ctx.Message
|
||||
@ -17,35 +14,27 @@ type SSH struct {
|
||||
*ctx.Context
|
||||
}
|
||||
|
||||
func (ssh *SSH) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
|
||||
c.Caches = map[string]*ctx.Cache{
|
||||
"hostname": &ctx.Cache{Name: "hostname", Value: "com", Help: "主机数量"},
|
||||
}
|
||||
func (ssh *SSH) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
|
||||
c.Caches = map[string]*ctx.Cache{}
|
||||
c.Configs = map[string]*ctx.Config{}
|
||||
|
||||
s := new(SSH)
|
||||
s.Context = c
|
||||
return s
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (ssh *SSH) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||
func (ssh *SSH) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
||||
ssh.Caches["hostname"] = &ctx.Cache{Name: "hostname", Value: "", Help: "主机数量"}
|
||||
if ssh.Context == Index {
|
||||
Pulse = m
|
||||
}
|
||||
return ssh
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (ssh *SSH) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
func (ssh *SSH) Start(m *ctx.Message, arg ...string) bool {
|
||||
ssh.nfs = m.Source()
|
||||
m.Cap("stream", m.Source().Name)
|
||||
return false
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (ssh *SSH) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||
func (ssh *SSH) Close(m *ctx.Message, arg ...string) bool {
|
||||
return false
|
||||
switch ssh.Context {
|
||||
case m.Target():
|
||||
@ -65,19 +54,14 @@ func (ssh *SSH) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
func Done(m *ctx.Message, lock chan bool) { // {{{
|
||||
func Done(m *ctx.Message, lock chan bool) {
|
||||
m.Log("lock", "done before %v", m.Meta["detail"])
|
||||
if m.Options("stdio") {
|
||||
lock <- true
|
||||
}
|
||||
m.Log("lock", "done after %v", m.Meta["detail"])
|
||||
}
|
||||
|
||||
// }}}
|
||||
func Wait(m *ctx.Message, lock chan bool) { // {{{
|
||||
func Wait(m *ctx.Message, lock chan bool) {
|
||||
m.Log("lock", "wait before %v", m.Meta["detail"])
|
||||
if m.Options("stdio") {
|
||||
<-lock
|
||||
@ -85,22 +69,21 @@ func Wait(m *ctx.Message, lock chan bool) { // {{{
|
||||
m.Log("lock", "wait after %v", m.Meta["detail"])
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
var Pulse *ctx.Message
|
||||
var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
Caches: map[string]*ctx.Cache{
|
||||
"nhost": &ctx.Cache{Name: "主机数量", Value: "0", Help: "主机数量"},
|
||||
"nhost": &ctx.Cache{Name: "主机数量", Value: "0", Help: "主机数量"},
|
||||
"domain": &ctx.Cache{Name: "domain", Value: "", Help: "主机域名"},
|
||||
|
||||
"route": &ctx.Cache{Name: "route", Value: "com", Help: "主机数量"},
|
||||
"count": &ctx.Cache{Name: "count", Value: "3", Help: "主机数量"},
|
||||
"share": &ctx.Cache{Name: "share", Value: "root", Help: "主机数量"},
|
||||
"level": &ctx.Cache{Name: "level", Value: "root", Help: "主机数量"},
|
||||
|
||||
"domain": &ctx.Cache{Name: "domain", Value: "com", Help: "主机数量"},
|
||||
},
|
||||
Configs: map[string]*ctx.Config{
|
||||
"hostname": &ctx.Config{Name: "hostname", Value: "com", Help: "主机数量"},
|
||||
|
||||
"interval": &ctx.Config{Name: "interval", Value: "3", Help: "主机数量"},
|
||||
"hostname": &ctx.Config{Name: "hostname", Value: "com", Help: "主机数量"},
|
||||
"domain.json": &ctx.Config{Name: "domain.json", Value: "var/domain.json", Help: "主机数量"},
|
||||
"domain.png": &ctx.Config{Name: "domain.png", Value: "var/domain.png", Help: "主机数量"},
|
||||
|
||||
@ -113,35 +96,48 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
"mark": &ctx.Config{Name: "mark", Value: "com", Help: "主机数量"},
|
||||
},
|
||||
Commands: map[string]*ctx.Command{
|
||||
"listen": &ctx.Command{Name: "listen address protocol", Help: "监听连接", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if _, ok := m.Target().Server.(*SSH); m.Assert(ok) { // {{{
|
||||
"listen": &ctx.Command{Name: "listen address [security [protocol]]", Help: "网络监听", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if _, ok := m.Target().Server.(*SSH); m.Assert(ok) {
|
||||
m.Sess("nfs").Call(func(sub *ctx.Message) *ctx.Message {
|
||||
sub.Start(fmt.Sprintf("host%d", Pulse.Capi("nhost", 1)), "远程主机")
|
||||
// sub.Spawn().Cmd("pwd", "init")
|
||||
return sub
|
||||
}, m.Meta["detail"])
|
||||
m.Spawn(m.Target()).Cmd("save")
|
||||
if !m.Caps("domain") {
|
||||
m.Cap("domain", m.Cap("hostname", m.Conf("hostname")))
|
||||
}
|
||||
// m.Spawn(m.Target()).Cmd("save")
|
||||
}
|
||||
// }}}
|
||||
}},
|
||||
"dial": &ctx.Command{Name: "dial address protocol", Help: "建立连接", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if _, ok := m.Target().Server.(*SSH); m.Assert(ok) { // {{{
|
||||
"dial": &ctx.Command{Name: "dial address [security [protocol]]", Help: "网络连接", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if _, ok := m.Target().Server.(*SSH); m.Assert(ok) {
|
||||
m.Sess("nfs").CallBack(true, func(sub *ctx.Message) *ctx.Message {
|
||||
sub.Target().Start(sub)
|
||||
sub.Spawn().Cmd("pwd", m.Conf("hostname"))
|
||||
return sub
|
||||
}, m.Meta["detail"])
|
||||
}
|
||||
// }}}
|
||||
}},
|
||||
"send": &ctx.Command{Name: "send [domain str] cmd arg...", Help: "远程执行",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if ssh, ok := m.Target().Server.(*SSH); m.Assert(ok) { // {{{
|
||||
if ssh, ok := m.Target().Server.(*SSH); m.Assert(ok) {
|
||||
domain := ""
|
||||
if len(arg) > 1 && arg[0] == "domain" {
|
||||
domain, arg = arg[1], arg[2:]
|
||||
domain = strings.TrimPrefix(strings.TrimPrefix(domain, m.Cap("domain")), ".")
|
||||
}
|
||||
|
||||
if m.Has("send_code") {
|
||||
msg := m.Spawn().Cmd(arg)
|
||||
m.Copy(msg, "result").Copy(msg, "append")
|
||||
} else {
|
||||
msg := m.Spawn(ssh.Message().Source())
|
||||
msg.Cmd("send", arg)
|
||||
m.Copy(msg, "result").Copy(msg, "append")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
if domain != "" {
|
||||
domain_miss := true
|
||||
host := strings.SplitN(domain, ".", 2)
|
||||
@ -197,36 +193,45 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
m.Copy(msg, "result").Copy(msg, "append")
|
||||
}
|
||||
return
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"pwd": &ctx.Command{Name: "pwd", Help: "远程执行", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if len(arg) == 0 { // {{{
|
||||
if m.Target() == c {
|
||||
m.Echo(m.Cap("domain"))
|
||||
} else {
|
||||
m.Echo("%s.%s", m.Cap("domain"), m.Cap("hostname"))
|
||||
if len(arg) > 0 {
|
||||
if m.Options("send_code") {
|
||||
if m.Target() == c {
|
||||
msg := m.Spawn().Cmd("send", "pwd", m.Confx("hostname", arg, 0))
|
||||
m.Cap("hostname", msg.Result(0))
|
||||
m.Cap("domain", msg.Result(1))
|
||||
} else {
|
||||
hostname := arg[0]
|
||||
m.Travel(func(m *ctx.Message, line int) bool {
|
||||
if hostname == m.Cap("hostname") {
|
||||
hostname += m.Cap("nhost")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}, c)
|
||||
m.Echo(m.Cap("hostname", hostname))
|
||||
m.Echo("%s.%s", m.Cap("domain"), m.Cap("hostname"))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if m.Target() == c {
|
||||
m.Conf("hostname", arg[0])
|
||||
msg := m.Spawn().Cmd("send", "pwd", arg[0])
|
||||
m.Cap("hostname", msg.Result(0))
|
||||
m.Cap("domain", msg.Result(1))
|
||||
} else {
|
||||
m.Spawn().Cmd("send", "pwd", arg[0])
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if m.Target() == c {
|
||||
msg := m.Spawn().Cmd("send", "pwd", arg[0])
|
||||
m.Copy(msg, "result").Copy(msg, "append")
|
||||
m.Cap("domain", msg.Result(0))
|
||||
} else if m.Options("send_code") {
|
||||
hostname := arg[0]
|
||||
m.Travel(func(m *ctx.Message, line int) bool {
|
||||
if hostname == m.Cap("hostname") {
|
||||
hostname += m.Cap("nhost")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}, c)
|
||||
m.Echo("%s.%s", m.Cap("domain"), m.Cap("hostname", hostname))
|
||||
} // }}}
|
||||
m.Echo(m.Cap("domain"))
|
||||
}},
|
||||
"hello": &ctx.Command{Name: "hello request", Help: "加密请求", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
aaa := m.Target().Message().Sess("aaa", false) // {{{
|
||||
aaa := m.Target().Message().Sess("aaa", false)
|
||||
for _, k := range m.Meta["seal"] {
|
||||
for i, v := range m.Meta[k] {
|
||||
m.Meta[k][i] = m.Spawn(aaa).Cmd("deal", v).Result(0)
|
||||
@ -252,14 +257,14 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
|
||||
msg := m.Spawn().Copy(m, "option").Cmd(arg)
|
||||
m.Copy(msg, "result").Copy(msg, "append")
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"shake": &ctx.Command{
|
||||
Name: "shake [domain host] cmd... [seal option...][encrypt option...]",
|
||||
Help: "加密通信",
|
||||
Form: map[string]int{"seal": -1, "encrypt": -1},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if ssh, ok := m.Target().Server.(*SSH); m.Assert(ok) { // {{{
|
||||
if ssh, ok := m.Target().Server.(*SSH); m.Assert(ok) {
|
||||
if len(arg) == 0 {
|
||||
for k, v := range ssh.peer {
|
||||
m.Echo("%s: %s\n", k, v.Cap("stream"))
|
||||
@ -304,7 +309,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
msg.Detail("send", args, "hello", arg)
|
||||
ssh.Message().Back(msg)
|
||||
m.Copy(msg, "result").Copy(msg, "append")
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"close": &ctx.Command{Name: "close", Help: "连接断开", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
m.Target().Close(m)
|
||||
@ -319,21 +324,21 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
}, c)
|
||||
}},
|
||||
"save": &ctx.Command{Name: "save", Help: "远程执行", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
json := m.Sess("nfs") // {{{
|
||||
json := m.Sess("nfs")
|
||||
json.Put("option", "data", map[string]string{"domain": m.Cap("domain")})
|
||||
json.Cmd("json", m.Conf("domain.json"))
|
||||
m.Sess("nfs").Cmd("genqr", m.Conf("domain.png"), json.Result(0))
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"who": &ctx.Command{Name: "who", Help: "远程执行", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
aaa := m.Sess("aaa") // {{{
|
||||
aaa := m.Sess("aaa")
|
||||
if aaa != nil {
|
||||
m.Echo(aaa.Cap("group"))
|
||||
}
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"good": &ctx.Command{Name: "good context|command|config|cache args", Help: "设备注册", Hand: func(m *ctx.Message, c *ctx.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 { // {{{
|
||||
if len(arg) == 0 {
|
||||
m.Append("share", m.Cap("share"))
|
||||
m.Append("level", m.Cap("level"))
|
||||
m.Append("type", m.Conf("type"))
|
||||
@ -399,7 +404,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
m.Add("append", "value", x.Value)
|
||||
m.Add("append", "help", x.Help)
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
package tcp // {{{
|
||||
// }}}
|
||||
import ( // {{{
|
||||
"contexts"
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"contexts"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
@ -10,22 +9,36 @@ import ( // {{{
|
||||
"strings"
|
||||
)
|
||||
|
||||
// }}}
|
||||
|
||||
type TCP struct {
|
||||
net.Conn
|
||||
net.Listener
|
||||
*ctx.Context
|
||||
}
|
||||
|
||||
func (tcp *TCP) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
|
||||
func (tcp *TCP) Read(b []byte) (n int, e error) {
|
||||
m := tcp.Context.Message()
|
||||
m.Assert(tcp.Conn != nil)
|
||||
n, e = tcp.Conn.Read(b)
|
||||
m.Capi("nrecv", n)
|
||||
m.Assert(e)
|
||||
return
|
||||
}
|
||||
func (tcp *TCP) Write(b []byte) (n int, e error) {
|
||||
m := tcp.Context.Message()
|
||||
m.Assert(tcp.Conn != nil)
|
||||
n, e = tcp.Conn.Write(b)
|
||||
m.Capi("nsend", n)
|
||||
m.Assert(e)
|
||||
return
|
||||
}
|
||||
|
||||
func (tcp *TCP) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
|
||||
c.Caches = map[string]*ctx.Cache{
|
||||
"protocol": &ctx.Cache{Name: "网络协议(tcp/tcp4/tcp6)", Value: m.Conf("protocol"), Help: "网络协议"},
|
||||
"certfile": &ctx.Cache{Name: "certfile", Value: "", Help: "加密通信"},
|
||||
"keyfile": &ctx.Cache{Name: "keyfile", Value: "", Help: "加密通信"},
|
||||
"address": &ctx.Cache{Name: "网络地址", Value: "", Help: "网络地址"},
|
||||
"nrecv": &ctx.Cache{Name: "nrecv", Value: "0", Help: "网络地址"},
|
||||
"nsend": &ctx.Cache{Name: "nsend", Value: "0", Help: "网络地址"},
|
||||
"protocol": &ctx.Cache{Name: "protocol(tcp/tcp4/tcp6)", Value: "", Help: "网络协议"},
|
||||
"security": &ctx.Cache{Name: "security(true/false)", Value: "", Help: "加密通信"},
|
||||
"address": &ctx.Cache{Name: "address", Value: "", Help: "网络地址"},
|
||||
"nrecv": &ctx.Cache{Name: "nrecv", Value: "0", Help: "接收字节数"},
|
||||
"nsend": &ctx.Cache{Name: "nsend", Value: "0", Help: "发送字节数"},
|
||||
}
|
||||
c.Configs = map[string]*ctx.Config{}
|
||||
|
||||
@ -33,22 +46,17 @@ func (tcp *TCP) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
|
||||
s.Context = c
|
||||
return s
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (tcp *TCP) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||
func (tcp *TCP) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
||||
return tcp
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (tcp *TCP) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
func (tcp *TCP) Start(m *ctx.Message, arg ...string) bool {
|
||||
m.Cap("address", m.Confx("address", arg, 1))
|
||||
m.Cap("certfile", m.Confx("certfile", arg, 2))
|
||||
m.Cap("keyfile", m.Confx("keyfile", arg, 3))
|
||||
m.Cap("protocol", m.Confx("protocol", arg, 4))
|
||||
m.Cap("security", m.Confx("security", arg, 2))
|
||||
m.Cap("protocol", m.Confx("protocol", arg, 3))
|
||||
|
||||
switch arg[0] {
|
||||
case "dial":
|
||||
if m.Caps("certfile") {
|
||||
if m.Caps("security") {
|
||||
m.Sess("aaa", m.Sess("aaa").Cmd("login", "cert", m.Cap("certfile"), "key", m.Cap("keyfile"), "tcp"))
|
||||
cert, e := tls.LoadX509KeyPair(m.Cap("certfile"), m.Cap("keyfile"))
|
||||
m.Assert(e)
|
||||
@ -64,20 +72,22 @@ func (tcp *TCP) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
}
|
||||
|
||||
m.Log("info", "%s dial %s", m.Cap("nclient"),
|
||||
m.Option("stream", m.Cap("stream", fmt.Sprintf("%s->%s", tcp.LocalAddr(), tcp.RemoteAddr()))))
|
||||
m.Put("option", "io", tcp.Conn).Back(m.Spawn(m.Source()))
|
||||
m.Cap("stream", fmt.Sprintf("%s->%s", tcp.LocalAddr(), tcp.RemoteAddr())))
|
||||
|
||||
m.Put("option", "io", tcp).Back(m.Spawn(m.Source()))
|
||||
return false
|
||||
case "accept":
|
||||
c, e := m.Data["io"].(net.Conn)
|
||||
c, e := m.Optionv("io").(net.Conn)
|
||||
m.Assert(e)
|
||||
tcp.Conn = c
|
||||
|
||||
m.Log("info", "%s accept %s", m.Cap("nclient"),
|
||||
m.Option("stream", m.Cap("stream", fmt.Sprintf("%s<-%s", tcp.LocalAddr(), tcp.RemoteAddr()))))
|
||||
m.Put("option", "io", tcp.Conn).Back(m.Spawn(m.Source()))
|
||||
m.Cap("stream", fmt.Sprintf("%s<-%s", tcp.LocalAddr(), tcp.RemoteAddr())))
|
||||
|
||||
m.Put("option", "io", tcp).Back(m.Spawn(m.Source()))
|
||||
return false
|
||||
default:
|
||||
if m.Caps("certfile") {
|
||||
if m.Caps("security") {
|
||||
m.Sess("aaa", m.Sess("aaa").Cmd("login", "cert", m.Cap("certfile"), "key", m.Cap("keyfile"), "tcp"))
|
||||
cert, e := tls.LoadX509KeyPair(m.Cap("certfile"), m.Cap("keyfile"))
|
||||
m.Assert(e)
|
||||
@ -92,23 +102,21 @@ func (tcp *TCP) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
tcp.Listener = l
|
||||
}
|
||||
|
||||
m.Log("info", "%d listen %v", m.Capi("nlisten"), m.Cap("stream", fmt.Sprintf("%s", tcp.Addr())))
|
||||
m.Log("info", "%d listen %v", m.Capi("nlisten"),
|
||||
m.Cap("stream", fmt.Sprintf("%s", tcp.Addr())))
|
||||
}
|
||||
|
||||
for {
|
||||
c, e := tcp.Accept()
|
||||
m.Assert(e)
|
||||
msg := m.Spawn(Index).Put("option", "io", c).Put("option", "source", m.Source())
|
||||
msg.Call(func(com *ctx.Message) *ctx.Message {
|
||||
m.Spawn(Index).Put("option", "io", c).Call(func(com *ctx.Message) *ctx.Message {
|
||||
return com.Spawn(m.Source())
|
||||
}, "accept", c.RemoteAddr().String(), m.Cap("security"), m.Cap("protocol"))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (tcp *TCP) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||
func (tcp *TCP) Close(m *ctx.Message, arg ...string) bool {
|
||||
return false
|
||||
switch tcp.Context {
|
||||
case m.Target():
|
||||
@ -136,15 +144,13 @@ func (tcp *TCP) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||
return true
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
var Index = &ctx.Context{Name: "tcp", Help: "网络中心",
|
||||
Caches: map[string]*ctx.Cache{
|
||||
"nlisten": &ctx.Cache{Name: "nlisten", Value: "0", Help: "监听数量"},
|
||||
"nclient": &ctx.Cache{Name: "nclient", Value: "0", Help: "连接数量"},
|
||||
},
|
||||
Configs: map[string]*ctx.Config{
|
||||
"address": &ctx.Config{Name: "address", Value: ":9090", Help: "加密通信"},
|
||||
"address": &ctx.Config{Name: "address", Value: ":9090", Help: "网络地址"},
|
||||
"security": &ctx.Config{Name: "security(true/false)", Value: "false", Help: "加密通信"},
|
||||
"protocol": &ctx.Config{Name: "protocol(tcp/tcp4/tcp6)", Value: "tcp4", Help: "网络协议"},
|
||||
},
|
||||
@ -159,53 +165,39 @@ var Index = &ctx.Context{Name: "tcp", Help: "网络中心",
|
||||
m.Start(fmt.Sprintf("com%d", m.Capi("nclient", 1)), "网络连接", m.Meta["detail"]...)
|
||||
}},
|
||||
"send": &ctx.Command{Name: "send message", Help: "发送消息", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if tcp, ok := m.Target().Server.(*TCP); m.Assert(ok) && tcp.Conn != nil { // {{{
|
||||
tcp.Conn.Write([]byte(arg[0]))
|
||||
m.Capi("nsend", len(arg[0]))
|
||||
} // }}}
|
||||
if tcp, ok := m.Target().Server.(*TCP); m.Assert(ok) {
|
||||
tcp.Write([]byte(arg[0]))
|
||||
}
|
||||
}},
|
||||
"recv": &ctx.Command{Name: "recv size", Help: "接收消息", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if tcp, ok := m.Target().Server.(*TCP); m.Assert(ok) && tcp.Conn != nil { // {{{
|
||||
size, e := strconv.Atoi(arg[0])
|
||||
if tcp, ok := m.Target().Server.(*TCP); m.Assert(ok) {
|
||||
n, e := strconv.Atoi(arg[0])
|
||||
m.Assert(e)
|
||||
buf := make([]byte, n)
|
||||
|
||||
buf := make([]byte, size)
|
||||
n, e := tcp.Conn.Read(buf)
|
||||
m.Assert(e)
|
||||
buf = buf[:n]
|
||||
|
||||
m.Echo(string(buf))
|
||||
m.Capi("nrecv", n)
|
||||
} // }}}
|
||||
n, _ = tcp.Read(buf)
|
||||
m.Echo(string(buf[:n]))
|
||||
}
|
||||
}},
|
||||
"ifconfig": &ctx.Command{Name: "ifconfig", Help: "网络配置", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
ifs, e := net.Interfaces() // {{{
|
||||
m.Assert(e)
|
||||
for _, v := range ifs {
|
||||
ips, e := v.Addrs()
|
||||
m.Assert(e)
|
||||
for _, x := range ips {
|
||||
ip := x.String()
|
||||
if !strings.Contains(ip, ":") && len(ip) > 0 && len(v.HardwareAddr) > 0 {
|
||||
m.Add("append", "index", v.Index)
|
||||
m.Add("append", "name", v.Name)
|
||||
m.Add("append", "hard", v.HardwareAddr)
|
||||
m.Add("append", "ip", ip)
|
||||
if ifs, e := net.Interfaces(); m.Assert(e) {
|
||||
for _, v := range ifs {
|
||||
if ips, e := v.Addrs(); m.Assert(e) {
|
||||
for _, x := range ips {
|
||||
ip := x.String()
|
||||
if !strings.Contains(ip, ":") && len(ip) > 0 && len(v.HardwareAddr) > 0 {
|
||||
m.Add("append", "index", v.Index)
|
||||
m.Add("append", "name", v.Name)
|
||||
m.Add("append", "hard", v.HardwareAddr)
|
||||
m.Add("append", "ip", ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m.Table()
|
||||
}
|
||||
m.Table()
|
||||
// }}}
|
||||
}},
|
||||
},
|
||||
Index: map[string]*ctx.Context{
|
||||
"void": &ctx.Context{
|
||||
Commands: map[string]*ctx.Command{
|
||||
"listen": &ctx.Command{},
|
||||
"dial": &ctx.Command{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package web // {{{
|
||||
// }}}
|
||||
import ( // {{{
|
||||
package web
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"contexts"
|
||||
"github.com/gomarkdown/markdown"
|
||||
@ -26,14 +26,11 @@ import ( // {{{
|
||||
"time"
|
||||
)
|
||||
|
||||
// }}}
|
||||
|
||||
type MUX interface {
|
||||
Handle(string, http.Handler)
|
||||
HandleFunc(string, func(http.ResponseWriter, *http.Request))
|
||||
Trans(*ctx.Message, string, func(*ctx.Message, *ctx.Context, string, ...string))
|
||||
}
|
||||
|
||||
type WEB struct {
|
||||
*http.ServeMux
|
||||
*http.Server
|
||||
@ -44,7 +41,7 @@ type WEB struct {
|
||||
*ctx.Context
|
||||
}
|
||||
|
||||
func (web *WEB) Merge(m *ctx.Message, uri string, arg ...string) string { // {{{
|
||||
func (web *WEB) Merge(m *ctx.Message, uri string, arg ...string) string {
|
||||
add, e := url.Parse(uri)
|
||||
m.Assert(e)
|
||||
adds := []string{m.Confx("protocol", add.Scheme, "%s://"), m.Confx("hostname", add.Host)}
|
||||
@ -86,9 +83,7 @@ func (web *WEB) Merge(m *ctx.Message, uri string, arg ...string) string { // {{{
|
||||
|
||||
return strings.Join(adds, "")
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (web *WEB) Trans(m *ctx.Message, key string, hand func(*ctx.Message, *ctx.Context, string, ...string)) { // {{{
|
||||
func (web *WEB) Trans(m *ctx.Message, key string, hand func(*ctx.Message, *ctx.Context, string, ...string)) {
|
||||
web.HandleFunc(key, func(w http.ResponseWriter, r *http.Request) {
|
||||
msg := m.Spawn()
|
||||
msg.TryCatch(msg, true, func(msg *ctx.Message) {
|
||||
@ -154,9 +149,7 @@ func (web *WEB) Trans(m *ctx.Message, key string, hand func(*ctx.Message, *ctx.C
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (web *WEB) ServeHTTP(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
func (web *WEB) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
m := web.Message().Log("info", "").Log("info", "%v %s %s", r.RemoteAddr, r.Method, r.URL)
|
||||
|
||||
if m.Confs("logheaders") {
|
||||
@ -186,10 +179,7 @@ func (web *WEB) ServeHTTP(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
m.Log("info", "")
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
func (web *WEB) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
|
||||
func (web *WEB) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
|
||||
c.Caches = map[string]*ctx.Cache{}
|
||||
c.Configs = map[string]*ctx.Config{}
|
||||
|
||||
@ -198,9 +188,7 @@ func (web *WEB) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
|
||||
s.cookie = web.cookie
|
||||
return s
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (web *WEB) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||
func (web *WEB) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
||||
web.Caches["route"] = &ctx.Cache{Name: "请求路径", Value: "/" + web.Context.Name + "/", Help: "请求路径"}
|
||||
web.Caches["register"] = &ctx.Cache{Name: "已初始化(yes/no)", Value: "no", Help: "模块是否已初始化"}
|
||||
web.Caches["master"] = &ctx.Cache{Name: "服务入口(yes/no)", Value: "no", Help: "服务入口"}
|
||||
@ -219,9 +207,7 @@ func (web *WEB) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||
}
|
||||
return web
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (web *WEB) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
func (web *WEB) Start(m *ctx.Message, arg ...string) bool {
|
||||
if len(arg) > 0 {
|
||||
m.Cap("directory", arg[0])
|
||||
}
|
||||
@ -307,9 +293,7 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// }}}
|
||||
func (web *WEB) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||
func (web *WEB) Close(m *ctx.Message, arg ...string) bool {
|
||||
switch web.Context {
|
||||
case m.Target():
|
||||
case m.Source():
|
||||
@ -317,8 +301,6 @@ func (web *WEB) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||
return true
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
Caches: map[string]*ctx.Cache{
|
||||
"nserve": &ctx.Cache{Name: "nserve", Value: "0", Help: "主机数量"},
|
||||
@ -531,7 +513,7 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
Name: "client address [output [editor]]",
|
||||
Help: "添加请求配置, address: 默认地址, output: 输出路径, editor: 编辑器",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if _, e := m.Target().Server.(*WEB); m.Assert(e) { // {{{
|
||||
if _, e := m.Target().Server.(*WEB); m.Assert(e) {
|
||||
if len(arg) == 0 {
|
||||
return
|
||||
}
|
||||
@ -553,13 +535,13 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
if m.Conf("editor", "editor", "vim", "文件编辑器"); len(arg) > 2 {
|
||||
m.Conf("editor", arg[2])
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"cookie": &ctx.Command{
|
||||
Name: "cookie [create]|[name [value]]",
|
||||
Help: "读写请求的Cookie, name: 变量名, value: 变量值",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { // {{{
|
||||
if web, ok := m.Target().Server.(*WEB); m.Assert(ok) {
|
||||
switch len(arg) {
|
||||
case 0:
|
||||
for k, v := range web.cookie {
|
||||
@ -583,14 +565,14 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
web.cookie[arg[0]] = &http.Cookie{Name: arg[0], Value: arg[1]}
|
||||
}
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"get": &ctx.Command{
|
||||
Name: "get [method GET|POST] [file name filename] url arg...",
|
||||
Help: "访问服务, method: 请求方法, file: 发送文件, url: 请求地址, arg: 请求参数",
|
||||
Form: map[string]int{"method": 1, "headers": 2, "file": 2, "body_type": 1, "body": 1, "fields": 1, "value": 1, "json_route": 1, "json_key": 1},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { // {{{
|
||||
if web, ok := m.Target().Server.(*WEB); m.Assert(ok) {
|
||||
if web.client == nil {
|
||||
web.client = &http.Client{}
|
||||
}
|
||||
@ -844,7 +826,7 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
if m.Table(); len(m.Meta["append"]) == 0 {
|
||||
m.Echo("%s", string(buf))
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"post": &ctx.Command{Name: "post", Help: "访问服务",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
@ -864,7 +846,7 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
case "linux":
|
||||
m.Spawn().Cmd("open", url)
|
||||
}
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"serve": &ctx.Command{
|
||||
Name: "serve [directory [address [protocol]]]",
|
||||
@ -876,7 +858,7 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
Name: "route script|template|directory route content",
|
||||
Help: "添加响应, script: 脚本响应, template: 模板响应, directory: 目录响应, route: 请求路由, content: 响应内容",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if mux, ok := m.Target().Server.(MUX); m.Assert(ok) { // {{{
|
||||
if mux, ok := m.Target().Server.(MUX); m.Assert(ok) {
|
||||
switch len(arg) {
|
||||
case 0:
|
||||
for k, v := range m.Target().Commands {
|
||||
@ -910,26 +892,26 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
mux.Handle(arg[1]+"/", http.StripPrefix(arg[1], http.FileServer(http.Dir(arg[2]))))
|
||||
}
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
}},
|
||||
"upload": &ctx.Command{Name: "upload file", Help: "上传文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
msg := m.Spawn(m.Target()) // {{{
|
||||
msg := m.Spawn(m.Target())
|
||||
msg.Cmd("get", "/upload", "method", "POST", "file", "file", arg[0])
|
||||
m.Copy(msg, "result")
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/library/": &ctx.Command{Name: "/library", Help: "网页门户", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
r := m.Optionv("request").(*http.Request) // {{{
|
||||
r := m.Optionv("request").(*http.Request)
|
||||
w := m.Optionv("response").(http.ResponseWriter)
|
||||
dir := path.Join(m.Conf("library_dir"), m.Option("path"))
|
||||
if s, e := os.Stat(dir); e == nil && !s.IsDir() {
|
||||
http.ServeFile(w, r, dir)
|
||||
return
|
||||
}
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/travel": &ctx.Command{Name: "/travel", Help: "文件上传", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
// r := m.Optionv("request").(*http.Request) // {{{
|
||||
// r := m.Optionv("request").(*http.Request)
|
||||
// w := m.Optionv("response").(http.ResponseWriter)
|
||||
|
||||
if !m.Options("dir") {
|
||||
@ -1020,10 +1002,10 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
}
|
||||
}
|
||||
m.Append("template", m.Conf("travel_main"), m.Conf("travel_tmpl"))
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/index/": &ctx.Command{Name: "/index", Help: "网页门户", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
r := m.Optionv("request").(*http.Request) // {{{
|
||||
r := m.Optionv("request").(*http.Request)
|
||||
w := m.Optionv("response").(http.ResponseWriter)
|
||||
|
||||
if login := m.Spawn().Cmd("/login"); login.Has("template") {
|
||||
@ -1065,10 +1047,10 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
//浏览目录
|
||||
m.Append("template", m.Append("username"))
|
||||
m.Option("page_title", "index")
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/create": &ctx.Command{Name: "/create", Help: "创建目录或文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
// if check := m.Spawn().Cmd("/share", "/upload", "dir", m.Option("dir")); !check.Results(0) { // {{{
|
||||
// if check := m.Spawn().Cmd("/share", "/upload", "dir", m.Option("dir")); !check.Results(0) {
|
||||
// m.Copy(check, "append")
|
||||
// return
|
||||
// }
|
||||
@ -1113,10 +1095,10 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
}
|
||||
}
|
||||
m.Append("redirect", m.Option("referer"))
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/share": &ctx.Command{Name: "/share arg...", Help: "资源共享", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if check := m.Spawn().Cmd("/check", "target", m.Option("module"), m.Optionv("share")); !check.Results(0) { // {{{
|
||||
if check := m.Spawn().Cmd("/check", "target", m.Option("module"), m.Optionv("share")); !check.Results(0) {
|
||||
m.Copy(check, "append")
|
||||
return
|
||||
}
|
||||
@ -1205,10 +1187,10 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
m.Add("append", "to", u)
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/check": &ctx.Command{Name: "/check arg...", Help: "权限检查, cache|config|command: 接口类型, name: 接口名称, args: 其它参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if login := m.Spawn().Cmd("/login"); login.Has("template") { // {{{
|
||||
if login := m.Spawn().Cmd("/login"); login.Has("template") {
|
||||
m.Echo("no").Copy(login, "append")
|
||||
return
|
||||
}
|
||||
@ -1219,10 +1201,10 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
}
|
||||
|
||||
m.Echo("ok")
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/login": &ctx.Command{Name: "/login", Help: "用户登录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if m.Options("sessid") { // {{{
|
||||
if m.Options("sessid") {
|
||||
if aaa := m.Sess("aaa").Cmd("login", m.Option("sessid")); aaa.Results(0) {
|
||||
m.Append("redirect", m.Option("referer"))
|
||||
m.Append("username", aaa.Cap("username"))
|
||||
@ -1242,10 +1224,10 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
m.Append("template", "login")
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/render": &ctx.Command{Name: "/render index", Help: "模板响应, main: 模板入口, tmpl: 附加模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
w := m.Optionv("response").(http.ResponseWriter) // {{{
|
||||
w := m.Optionv("response").(http.ResponseWriter)
|
||||
w.Header().Add("Content-Type", "text/html")
|
||||
m.Optioni("ninput", 0)
|
||||
|
||||
@ -1307,10 +1289,10 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
}
|
||||
}
|
||||
m.Assert(tpl.ExecuteTemplate(w, "tail", m))
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/json": &ctx.Command{Name: "/json", Help: "json响应", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
w := m.Optionv("response").(http.ResponseWriter) // {{{
|
||||
w := m.Optionv("response").(http.ResponseWriter)
|
||||
|
||||
meta := map[string]interface{}{}
|
||||
if len(m.Meta["result"]) > 0 {
|
||||
@ -1337,18 +1319,20 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
|
||||
m.Log("json", "won %v", string(b))
|
||||
w.Write(b)
|
||||
}
|
||||
// }}}
|
||||
|
||||
}},
|
||||
"/paste": &ctx.Command{Name: "/paste", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if login := m.Spawn().Cmd("/login"); login.Has("redirect") {
|
||||
m.Sess("cli").Cmd("system", "tmux", "set-buffer", "-b", "0", m.Option("content"))
|
||||
}
|
||||
|
||||
}},
|
||||
"/blog": &ctx.Command{Name: "/blog", Help: "博客", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if m.Has("title") && m.Has("content") {
|
||||
}
|
||||
|
||||
m.Echo("blog service")
|
||||
|
||||
}},
|
||||
"/wiki_tags": &ctx.Command{Name: "/wiki_tags ", Help: "博客", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||
if len(arg) > 0 {
|
||||
|
@ -134,6 +134,24 @@ $ sftp shy@10.0.0.10
|
||||
- 公钥文件 ~/.ssh/id_rsa.pub
|
||||
- 授权公钥 ~/.ssh/authorized_keys
|
||||
|
||||
#### 编译代码
|
||||
计算机由硬件与软件组成,软件又分为操作系统与应用程序。
|
||||
|
||||
无论是Linux,还是MacOSX,还是Windows,操作系统给应用程序提供了API接口。
|
||||
应用程序通过调用这些API接口,实现各种各样的功能。
|
||||
|
||||
如果现有的工具不能满足需求时,就需要下载工具的源码进行定制编译,或是开发一些模块。
|
||||
|
||||
API
|
||||
|
||||
|
||||
|
||||
##### Makefile
|
||||
make命令根据Makefile文件中定义的规则,调用各种命令,来生成目标文件。
|
||||
可以用来调用编译器,将项目的源码文件,编译成可执行文件。
|
||||
将源码文件编译成可执行文件。
|
||||
[Makefile官方文档](https://www.gnu.org/software/make/manual/make.html)
|
||||
<>
|
||||
|
||||
#### 本地化
|
||||
|
||||
|
@ -838,12 +838,12 @@ docker以容器的形式,将程序运行的所有环境,打包成一个独
|
||||
与VMware或是VirtualBox之类的虚拟机相比,docker更加轻量,docker中的进程和本机进程一样,docker中的文件和本机文件一样,docker只是将它们组织在一起。
|
||||
而不像虚拟机一样,需要虚拟出一个完整的操作系统,并提供一堆设备驱动程序,一台普通的电脑开几个虚拟机资源就不足了,但docker却像进程一样占有很少的资源,可以运行很多容器。
|
||||
|
||||
docker分为企业版EE,社区版CE,对于个人使用社会版即可。更多信息参考:[docker官网](https://docs.docker.com/)
|
||||
docker分为企业版EE,社区版CE,对于个人使用社区版即可。更多信息参考:[docker官网](https://docs.docker.com/)
|
||||
|
||||
- [Windows版docker下载](https://store.docker.com/editions/community/docker-ce-desktop-windows)
|
||||
- [Mac版docker下载](https://store.docker.com/editions/community/docker-ce-desktop-mac)
|
||||
|
||||
Ubuntu上安装docker
|
||||
Ubuntu上安装docker,还需要将docker官网加到软件源中
|
||||
```
|
||||
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
$ sudo add-apt-repository \
|
||||
@ -854,256 +854,310 @@ $ sudo apt-get update
|
||||
$ sudo apt-get install docker-ce
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 入门体验
|
||||
如下示例,run命令用busybox镜像,启动了docker的一个容器。
|
||||
```
|
||||
$ docker
|
||||
Usage: docker [OPTIONS] COMMAND
|
||||
|
||||
A self-sufficient runtime for containers
|
||||
|
||||
Options:
|
||||
--config string Location of client config files (default "/Users/shaoying/.docker")
|
||||
-D, --debug Enable debug mode
|
||||
-H, --host list Daemon socket(s) to connect to
|
||||
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
|
||||
--tls Use TLS; implied by --tlsverify
|
||||
--tlscacert string Trust certs signed only by this CA (default "/Users/shaoying/.docker/ca.pem")
|
||||
--tlscert string Path to TLS certificate file (default "/Users/shaoying/.docker/cert.pem")
|
||||
--tlskey string Path to TLS key file (default "/Users/shaoying/.docker/key.pem")
|
||||
--tlsverify Use TLS and verify the remote
|
||||
-v, --version Print version information and quit
|
||||
|
||||
Management Commands:
|
||||
checkpoint Manage checkpoints
|
||||
config Manage Docker configs
|
||||
container Manage containers
|
||||
image Manage images
|
||||
network Manage networks
|
||||
node Manage Swarm nodes
|
||||
plugin Manage plugins
|
||||
secret Manage Docker secrets
|
||||
service Manage services
|
||||
stack Manage Docker stacks
|
||||
swarm Manage Swarm
|
||||
system Manage Docker
|
||||
trust Manage trust on Docker images
|
||||
volume Manage volumes
|
||||
|
||||
Commands:
|
||||
attach Attach local standard input, output, and error streams to a running container
|
||||
build Build an image from a Dockerfile
|
||||
commit Create a new image from a container's changes
|
||||
cp Copy files/folders between a container and the local filesystem
|
||||
create Create a new container
|
||||
deploy Deploy a new stack or update an existing stack
|
||||
diff Inspect changes to files or directories on a container's filesystem
|
||||
events Get real time events from the server
|
||||
exec Run a command in a running container
|
||||
export Export a container's filesystem as a tar archive
|
||||
history Show the history of an image
|
||||
images List images
|
||||
import Import the contents from a tarball to create a filesystem image
|
||||
info Display system-wide information
|
||||
inspect Return low-level information on Docker objects
|
||||
kill Kill one or more running containers
|
||||
load Load an image from a tar archive or STDIN
|
||||
login Log in to a Docker registry
|
||||
logout Log out from a Docker registry
|
||||
logs Fetch the logs of a container
|
||||
pause Pause all processes within one or more containers
|
||||
port List port mappings or a specific mapping for the container
|
||||
ps List containers
|
||||
pull Pull an image or a repository from a registry
|
||||
push Push an image or a repository to a registry
|
||||
rename Rename a container
|
||||
restart Restart one or more containers
|
||||
rm Remove one or more containers
|
||||
rmi Remove one or more images
|
||||
run Run a command in a new container
|
||||
save Save one or more images to a tar archive (streamed to STDOUT by default)
|
||||
search Search the Docker Hub for images
|
||||
start Start one or more stopped containers
|
||||
stats Display a live stream of container(s) resource usage statistics
|
||||
stop Stop one or more running containers
|
||||
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
|
||||
top Display the running processes of a container
|
||||
unpause Unpause all processes within one or more containers
|
||||
update Update configuration of one or more containers
|
||||
version Show the Docker version information
|
||||
wait Block until one or more containers stop, then print their exit codes
|
||||
|
||||
Run 'docker COMMAND --help' for more information on a command.
|
||||
$ docker run -it busybox
|
||||
Unable to find image 'busybox:latest' locally
|
||||
latest: Pulling from library/busybox
|
||||
8c5a7da1afbc: Pull complete
|
||||
Digest: sha256:cb63aa0641a885f54de20f61d152187419e8f6b159ed11a251a09d115f_f9bd
|
||||
Status: Downloaded newer image for busybox:latest
|
||||
/ #
|
||||
```
|
||||
这里本机并没有busybox的镜像,所以docker自动从dockhub上,下载了busybox的镜像,并用这个镜像启动了一个容器。
|
||||
像github共享代码一样,dockhub上也共享了各种系统镜像,用户可以自由的下载与上传。
|
||||
|
||||
run命令需要一个参数,指定镜像的名称与版本,这里镜像的名字为busybox,默认的版本为latest,即最新版。
|
||||
busybox是将Unix下的常用命令经过挑选裁剪集成到一个程序中,搭配Linux内核就可以做出一个小型的操作系统,在嵌入式领域应用广泛。
|
||||
体积小到只有1M左右,下载很快,所以这里用做示例。更多信息参考[busybox官网](https://busybox.net/)
|
||||
|
||||
"/ #",看到最后一行的的命令提示符,就知道容器已经启动了,就可以在这个容器的shell中,执行各种命令与操作了。最后用Ctrl+D或关闭终端窗口,就可以结束容器。
|
||||
再次运行run,又可以重新启动容器。
|
||||
|
||||
|
||||
|
||||
如下示例,除了交互式启动容器,还可以用守护的方式启动容器。
|
||||
```
|
||||
$ docker
|
||||
Usage: docker [OPTIONS] COMMAND
|
||||
|
||||
A self-sufficient runtime for containers
|
||||
|
||||
Options:
|
||||
--config string Location of client config files (default "/Users/shaoying/.docker")
|
||||
-D, --debug Enable debug mode
|
||||
-H, --host list Daemon socket(s) to connect to
|
||||
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
|
||||
--tls Use TLS; implied by --tlsverify
|
||||
--tlscacert string Trust certs signed only by this CA (default "/Users/shaoying/.docker/ca.pem")
|
||||
--tlscert string Path to TLS certificate file (default "/Users/shaoying/.docker/cert.pem")
|
||||
--tlskey string Path to TLS key file (default "/Users/shaoying/.docker/key.pem")
|
||||
--tlsverify Use TLS and verify the remote
|
||||
-v, --version Print version information and quit
|
||||
|
||||
Management Commands:
|
||||
checkpoint Manage checkpoints
|
||||
node Manage Swarm nodes
|
||||
plugin Manage plugins
|
||||
secret Manage Docker secrets
|
||||
service Manage services
|
||||
stack Manage Docker stacks
|
||||
swarm Manage Swarm
|
||||
trust Manage trust on Docker images
|
||||
|
||||
Commands:
|
||||
attach Attach local standard input, output, and error streams to a running container
|
||||
build Build an image from a Dockerfile
|
||||
commit Create a new image from a container's changes
|
||||
cp Copy files/folders between a container and the local filesystem
|
||||
create Create a new container
|
||||
deploy Deploy a new stack or update an existing stack
|
||||
diff Inspect changes to files or directories on a container's filesystem
|
||||
events Get real time events from the server
|
||||
exec Run a command in a running container
|
||||
export Export a container's filesystem as a tar archive
|
||||
history Show the history of an image
|
||||
images List images
|
||||
import Import the contents from a tarball to create a filesystem image
|
||||
info Display system-wide information
|
||||
inspect Return low-level information on Docker objects
|
||||
kill Kill one or more running containers
|
||||
load Load an image from a tar archive or STDIN
|
||||
login Log in to a Docker registry
|
||||
logout Log out from a Docker registry
|
||||
logs Fetch the logs of a container
|
||||
pause Pause all processes within one or more containers
|
||||
port List port mappings or a specific mapping for the container
|
||||
ps List containers
|
||||
pull Pull an image or a repository from a registry
|
||||
push Push an image or a repository to a registry
|
||||
rename Rename a container
|
||||
restart Restart one or more containers
|
||||
rm Remove one or more containers
|
||||
rmi Remove one or more images
|
||||
run Run a command in a new container
|
||||
save Save one or more images to a tar archive (streamed to STDOUT by default)
|
||||
search Search the Docker Hub for images
|
||||
start Start one or more stopped containers
|
||||
stats Display a live stream of container(s) resource usage statistics
|
||||
stop Stop one or more running containers
|
||||
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
|
||||
top Display the running processes of a container
|
||||
unpause Unpause all processes within one or more containers
|
||||
update Update configuration of one or more containers
|
||||
version Show the Docker version information
|
||||
wait Block until one or more containers stop, then print their exit codes
|
||||
|
||||
Run 'docker COMMAND --help' for more information on a command.
|
||||
$ docker run -dt --name demo busybox
|
||||
d71c8e37bcc153db239f8b1eccb5fa53d202df84d3ffa7ae4e7f8c051d0d481a
|
||||
```
|
||||
- "-dt",指定容器守护的方式运行,即使终端窗口关闭了,守护式的容器会在后台一直运行,可以被反复连接使用。
|
||||
- "--name demo",指定了容器的名字为demo,每个容器启动后docker会生成一个sha256的哈希值,如这里的"d71c8e37bcc153db239f8b1eccb5fa53d202df84d3ffa7ae4e7f8c051d0d481a"
|
||||
在之后的命令中,参数中需要指定容器的地方,都可以这个sha256的哈希值,也可以只写出前几位。但为了方便记忆,可以给容器指定名字。
|
||||
- "busybox",指定镜像名字与版本
|
||||
|
||||
镜像管理
|
||||
image Manage images
|
||||
|
||||
容器管理
|
||||
container Manage containers
|
||||
|
||||
配置管理
|
||||
config Manage Docker configs
|
||||
|
||||
系统管理
|
||||
system Manage Docker
|
||||
|
||||
网络管理
|
||||
network Manage networks
|
||||
|
||||
磁盘管理
|
||||
volume Manage volumes
|
||||
|
||||
#### docker镜像管理
|
||||
|
||||
- 查看镜像 docker image ls
|
||||
- 下载镜像 docker image pull
|
||||
|
||||
刚安装docker后,查看镜像列表,如下为空。
|
||||
```
|
||||
$ docker image ls
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
```
|
||||
像github管理代码仓库一样,docker hub上也存放了很多镜像,用户可以自由的下载与上传各种镜像。
|
||||
如下示例,下载一个busybox镜像。busybox是将Unix下的常用命令经过挑选裁剪集成一个程序中,搭配Linux内核就可以做出一个小型的操作系统,在嵌入式领域应用广泛。
|
||||
体积很小不到1M,下载很快,所以这里用做示例。更多信息参考[busybox官网](https://busybox.net/)
|
||||
```
|
||||
$ docker image pull busybox
|
||||
```
|
||||
下载完成后,再查看镜像列表,就会看到busybox镜像相关的信息。
|
||||
```
|
||||
$ docker image ls
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
busybox latest e1ddd7948a1c 6 weeks ago 1.16MB
|
||||
```
|
||||
#### docker容器管理
|
||||
|
||||
- 查看容器 docker ps
|
||||
- 启动容器 docker run
|
||||
- 停止容器 docker exec
|
||||
- 停止容器 docker stop
|
||||
|
||||
如下示例,查看容器列表,因为还没启动任何容器,所以这里为空。
|
||||
如下示例,ps命令可以查看正在运行的容器。
|
||||
```
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
d71c8e37bcc1 busybox "sh" 14 seconds ago Up 13 seconds demo
|
||||
```
|
||||
如下示例,用busybox:latest镜像,启动一个容器,并调用sh命令。
|
||||
如下示例,top命令可以查看某容器中运行的进程
|
||||
```
|
||||
$ docker run --name demo -dt busybox:latest sh
|
||||
29ff6b8343c4a2c57eab297e74e62422ab9bbd481d69f5ebf108f4aa23ae835c
|
||||
```
|
||||
其中,-d 指用守护的方式启动,与交互式 -i 不同,守护式启动,容器可以一直运行,不会因为终端容器关闭而停止。
|
||||
--name参数,指定容器的名字为demo,docker中标识容器有两种方式,一是通过ID查找容器,二是通过NAMES查找容器,为了方便记忆与查找,建议启动容器时加上名字参数。
|
||||
|
||||
如下示例,再次查看容器列表,看到容器已经启动。
|
||||
```
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
29ff6b8343c4 busybox:latest "sh" 4 minutes ago Up 4 minutes demo
|
||||
$ docker top demo
|
||||
PID USER TIME COMMAND
|
||||
4163 root 0:00 sh
|
||||
```
|
||||
|
||||
连接容器demo,调用命令解析器sh。这样就连接上了容器的命令行,可以执行各种命令。
|
||||
如下示例,exec可以在容器中运行各种命令,并将命令输出到当前终端。
|
||||
```
|
||||
$ docker exec demo uname
|
||||
Linux
|
||||
$ docker exec demo hostname
|
||||
d71c8e37bcc1
|
||||
```
|
||||
如下示例,还可以连接容器,启动一个交互shell。Ctrl+D或是关闭终端窗口,只会结束当前shell,容器依然还在后台继续运行。还可以被反复连接。
|
||||
```
|
||||
$ docker exec -it demo sh
|
||||
#
|
||||
/ #
|
||||
```
|
||||
如下示例,还可以对容器进行重命名。可以用ps命令查看,新名字已经生效。
|
||||
```
|
||||
$ docker rename demo demo1
|
||||
```
|
||||
|
||||
容器的停止,退出连接后,容器依然在后台运行,可以反复被连接。如果想停止容器的运行就用stop命令。
|
||||
容器中的根文件系统与本机的文件系统是完全隔离的,所以才能提供给容器中应用一个独立的运行环境。
|
||||
|
||||
如下示例,可以将本机文件复制到容器中。
|
||||
```
|
||||
$ docker stop demo
|
||||
$ docker cp ~/.vimrc demo1:/root
|
||||
$ docker exec demo1 ls -a /root
|
||||
.
|
||||
..
|
||||
.vimrc
|
||||
```
|
||||
如下示例,可以将容器中文件复制到本机。
|
||||
```
|
||||
$ docker cp demo1:/root vimrc
|
||||
$ ls
|
||||
vimrc
|
||||
```
|
||||
|
||||
#### 挂载文件
|
||||
之前启动的容器都是与本机之间没有什么交互,是一个完全独立的运行环境。
|
||||
如果需要容器与本机交互一些文件,就可以在启动容器时指定文件参数。
|
||||
如下示例,停止容器
|
||||
```
|
||||
$ docker run --name demo1 -v/Users/shaoying:/home/shaoying -dt busybox:latest sh
|
||||
$ docker stop demo1
|
||||
```
|
||||
|
||||
#### 端口映射
|
||||
ps命令默认只查看正在运行的容器,如果要查看已经停止的容器可以加参数-a
|
||||
```
|
||||
$ docker ps -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
513a5e1fc6f4 busybox "sh" 4 minutes ago Exited (137) 3 seconds ago demo1
|
||||
```
|
||||
|
||||
如下示例,已经停止的容器,还可以再启动,继续运行。
|
||||
```
|
||||
$ docker start demo1
|
||||
```
|
||||
|
||||
如下示例,如果确定已经停止的容器,不会再次启动使用,可以删除掉。
|
||||
```
|
||||
$ docker rm demo1
|
||||
```
|
||||
|
||||
#### 镜像管理
|
||||
```
|
||||
docker images
|
||||
image Manage images
|
||||
|
||||
images List images
|
||||
search Search the Docker Hub for images
|
||||
pull Pull an image or a repository from a registry
|
||||
push Push an image or a repository to a registry
|
||||
save Save one or more images to a tar archive (streamed to STDOUT by default)
|
||||
load Load an image from a tar archive or STDIN
|
||||
rmi Remove one or more images
|
||||
|
||||
history Show the history of an image
|
||||
build Build an image from a Dockerfile
|
||||
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
|
||||
```
|
||||
|
||||
#### 容器管理
|
||||
```
|
||||
stats Display a live stream of container(s) resource usage statistics
|
||||
attach Attach local standard input, output, and error streams to a running container
|
||||
container Manage containers
|
||||
commit Create a new image from a container's changes
|
||||
diff Inspect changes to files or directories on a container's filesystem
|
||||
kill Kill one or more running containers
|
||||
wait Block until one or more containers stop, then print their exit codes
|
||||
create Create a new container
|
||||
pause Pause all processes within one or more containers
|
||||
unpause Unpause all processes within one or more containers
|
||||
export Export a container's filesystem as a tar archive
|
||||
import Import the contents from a tarball to create a filesystem image
|
||||
logs Fetch the logs of a container
|
||||
restart Restart one or more containers
|
||||
update Update configuration of one or more containers
|
||||
volume Manage volumes
|
||||
network Manage networks
|
||||
```
|
||||
|
||||
#### 系统管理
|
||||
```
|
||||
deploy Deploy a new stack or update an existing stack
|
||||
version Show the Docker version information
|
||||
system Manage Docker
|
||||
info Display system-wide information
|
||||
login Log in to a Docker registry
|
||||
logout Log out from a Docker registry
|
||||
inspect Return low-level information on Docker objects
|
||||
secret Manage Docker secrets
|
||||
trust Manage trust on Docker images
|
||||
```
|
||||
|
||||
#### 集群管理
|
||||
```
|
||||
config Manage Docker configs
|
||||
checkpoint Manage checkpoints
|
||||
plugin Manage plugins
|
||||
service Manage services
|
||||
swarm Manage Swarm
|
||||
node Manage Swarm nodes
|
||||
stack Manage Docker stacks
|
||||
```
|
||||
|
||||
### git使用
|
||||
软件的开发是不断的迭代,不断的优化,不断的升级,是一个循序渐进的过程。
|
||||
所以需要对代码进行版本管理,记录每次提交的代码,可以随时查看变化与切换版本。
|
||||
|
||||
软件开发有时需要同时进行多个任务,如在开发新功能时,需要修复线上bug,所以需要分支管理。
|
||||
一般一个项目中至少会有三种分支:master、feature、bugfix。
|
||||
|
||||
此外软件开发的项目都一般是由团队完成,要多人协作共同完成功能开发,所以需要仓库管理,管理多人的代码。
|
||||
|
||||
git就是这样一种开源的代码管理工具,可以用来管理代码的版本、分支、仓库等。
|
||||
|
||||
### git入门
|
||||
Mac上自带git,不需要安装。
|
||||
Windows上安装了的git-scm,也集成了git,也不需要单独安装。
|
||||
但Ubuntu需要自己安装一下。
|
||||
```
|
||||
$ sudo apt-get install git
|
||||
```
|
||||
#### git 基础入门
|
||||
git help tutorial
|
||||
git help everyday
|
||||
git help workflows
|
||||
git help glossary
|
||||
|
||||
git是一个命令集合,有很多子命令,可以通过help命令来查看。
|
||||
```
|
||||
$ git help
|
||||
```
|
||||
|
||||
git init
|
||||
git status
|
||||
git diff
|
||||
git add
|
||||
git mv
|
||||
git rm
|
||||
git reset
|
||||
git commit
|
||||
git checkout
|
||||
git blame
|
||||
git log
|
||||
git tag
|
||||
|
||||
git branch
|
||||
git merge
|
||||
git rebase
|
||||
|
||||
git config
|
||||
git clone
|
||||
git remote
|
||||
git revert
|
||||
git fetch
|
||||
git pull
|
||||
git push
|
||||
|
||||
git bisect
|
||||
git grep
|
||||
git show
|
||||
|
||||
|
||||
add merge-octopus
|
||||
add--interactive merge-one-file
|
||||
am merge-ours
|
||||
annotate merge-recursive
|
||||
apply merge-resolve
|
||||
archimport merge-subtree
|
||||
archive merge-tree
|
||||
bisect mergetool
|
||||
bisect--helper mktag
|
||||
blame mktree
|
||||
branch mv
|
||||
bundle name-rev
|
||||
cat-file notes
|
||||
check-attr p4
|
||||
check-ignore pack-objects
|
||||
check-mailmap pack-redundant
|
||||
check-ref-format pack-refs
|
||||
checkout patch-id
|
||||
checkout-index prune
|
||||
cherry prune-packed
|
||||
cherry-pick pull
|
||||
citool push
|
||||
clean quiltimport
|
||||
clone read-tree
|
||||
column rebase
|
||||
commit receive-pack
|
||||
commit-tree reflog
|
||||
config relink
|
||||
count-objects remote
|
||||
credential remote-ext
|
||||
credential-cache remote-fd
|
||||
credential-cache--daemon remote-ftp
|
||||
credential-osxkeychain remote-ftps
|
||||
credential-store remote-http
|
||||
cvsexportcommit remote-https
|
||||
cvsimport remote-testsvn
|
||||
cvsserver repack
|
||||
daemon replace
|
||||
describe request-pull
|
||||
diff rerere
|
||||
diff-files reset
|
||||
diff-index rev-list
|
||||
diff-tree rev-parse
|
||||
difftool revert
|
||||
difftool--helper rm
|
||||
fast-export send-email
|
||||
fast-import send-pack
|
||||
fetch sh-i18n--envsubst
|
||||
fetch-pack shell
|
||||
filter-branch shortlog
|
||||
fmt-merge-msg show
|
||||
for-each-ref show-branch
|
||||
format-patch show-index
|
||||
fsck show-ref
|
||||
fsck-objects stage
|
||||
gc stash
|
||||
get-tar-commit-id status
|
||||
grep stripspace
|
||||
gui--askpass submodule
|
||||
hash-object submodule--helper
|
||||
help subtree
|
||||
http-backend svn
|
||||
http-fetch symbolic-ref
|
||||
http-push tag
|
||||
imap-send unpack-file
|
||||
index-pack unpack-objects
|
||||
init update-index
|
||||
init-db update-ref
|
||||
instaweb update-server-info
|
||||
interpret-trailers upload-archive
|
||||
log upload-pack
|
||||
ls-files var
|
||||
ls-remote verify-commit
|
||||
ls-tree verify-pack
|
||||
mailinfo verify-tag
|
||||
mailsplit web--browse
|
||||
merge whatchanged
|
||||
merge-base worktree
|
||||
merge-file write-tree
|
||||
merge-index
|
||||
|
||||
### vim入门
|
||||
Mac上自带vim,不需要安装。
|
||||
Windows上安装了的git-scm,也集成了vim,也不需要单独安装。
|
||||
|
Loading…
x
Reference in New Issue
Block a user