1
0
mirror of https://shylinux.com/x/ContextOS synced 2025-04-25 16:58:06 +08:00

mac pro tcp

This commit is contained in:
shaoying 2018-10-08 09:34:23 +08:00
parent 5f7d55da1a
commit 15d4da1b18
8 changed files with 670 additions and 809 deletions

View File

@ -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

View File

@ -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
} // }}}
}
}},
},
}

View File

@ -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)
}
} // }}}
}
}},
},
}

View File

@ -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() {

View File

@ -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 {

View File

@ -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)
<>
#### 本地化

View File

@ -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参数指定容器的名字为demodocker中标识容器有两种方式一是通过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也不需要单独安装。